“欧几里得”算法求两个数的最大公因数和用“艾拉托尼筛选法”求n以内的所有质数以及引发的new操作符能申请到多少内存空间的问题

a和b的约数整除他们的余数。
1.“欧几里得”算法求两个数的最大公因数


#include "stdafx.h"
#include<iostream>
using namespace std;

int main()
{
	int a, b,temp=1;
	cout << "请输入两个数" << endl;
	cin >> a >> b;
	while(b!=0)
	{
		temp = a%b;
		a = b;
		b = temp;
	}
	cout <<"最大公倍数为:"<< a<<endl;

	return 0;
}

原理如下:
很早就学过欧几里得算法,但是一直不知道它的原理。几乎每本算法书都会提到它,但是貌似只有数学书上才会见到它的原理。。。

前段时间粗粗看了点数论,惊讶于这个原理的奇妙。现在把它通俗地写下来,以免自己忘记。

欧几里得算法是求两个数的最大公约数(Greatest Common Divisor (GCD))的算法,我们首先假设有两个数 a 和 b,其中 a 是不小于 b 的数,

记 a 被 b 除的余数为 r,那么 a 可以写成这样的形式:

a=bq+r

其中 q 是整数。

现在假设 a 和 b 的一个约数为 u,那么 a 和 b 都能被 u 整除,即

a=su
b=tu

s和t都是整数

这样可以得出

r=a-bq=su-(tu)q=(s-tq)u

所以 r 也能被 u 整除,一般规律如下

a 和 b 的约数也整除它们的余数 r,所以 a 和 b 的任一约数同时也是 b 和 r 的约数。 —— 条件一

反过来可以得出

b 和 r 的任一约数同时也是 a 和 b 的约数。 ——条件二

这是因为对 b 和 r 每一个约数 v,有

b=kv
r=cv

于是有

a=bq+r=(kv)q+cv=(kq+c)v

由条件一和条件二可知

a 和 b 的约数的集合,全等于 b 和 r 的约数的集合。

于是

a 和 b 的最大公约数,就是 b 和 r 的最大公约数。

接下来用递推法,

a ÷ b 余 r,现在设

b ÷ r 余 r1

r ÷ r1 余 r2

……

r(n-3) ÷ r(n-2) 余 r(n-1)

r(n-2) ÷ r(n-1) 余 r(n)

因为 a>=b,可以看出余数 r(n) 会越来越小,最终变成 0.
当 r(n-1)≠0 且 r(n) = 0 时,可知 r(n-2) 可被 r(n-1) 整除,此时他俩的约数就只有:r(n-1) 和 r(n-1) 的因数,所以他们的最大公约数就是 r(n-1)!

所以 r(n-1) 就是 a 和 b 的最大公约数。(若 r = 0,则 b 为最大公约数)
可以发现这里没有要求 M>=N,这是因为如果那样,循环会自动交换它们的值。
转自这里

2.用“艾拉托尼筛选法”求n以内的所有质数

#include "stdafx.h"
#include<math.h>
#include<iostream>
using std::cout;

int main()
{
	int n,count = 0;
	int temp;

	printf("查询n以内的质数,请输入n:\n");
	scanf("%d", &n);
	
	int* arr=NULL;
	try
	{
		arr = new int[n+1];
	}
	catch (const std::bad_alloc &e)
	{
		cout << "申请内存失败" << std::endl;
	}
	
	if (arr == 0) // 有的编译器不能捕捉到new申请失败时抛出的异常,所以判断一下arr是否为空
		cout << "申请内存失败" << std::endl;


	int sqrtn = (int)sqrt(n);

	//为数组赋值,将每个数组成员下标分别赋值给自己
	for (int i = 0; i <=n; i++)
	{
		arr[i] = i;
		cout << i << std::endl;
	}

	//利用埃拉托色尼筛选法,将不是质数的数赋值为0
	for (int p= 2; p <= sqrtn; p++)
	{
		temp = p*p;
		while (temp <= n)
		{
			arr[temp] = 0;  //用0标志它不是质数
			temp = temp + p;
		}

	}

	//打印所有质数
	for (int i = 2; i <= n; i++)
	{
		if (arr[i] != 0)
		{
			count += 1;
			printf("第%d个质数:%d\n",count, i);
			
		}	
	}
	printf("一共有质数%d个", count);
	delete arr;

	return 0;
}


这里因为是用new来动态申请空间,所以可能会涉及到内存申请失败的可能。
知道new是在堆上面分配空间,是否new申请空间的上限即是堆的上限?new能最多能申请到多少的空间呢?因编译器而异?还是因操作系统而异?或者两者都有?

于是去别人院子里剽窃了一波:
1.栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等,其操作方式类似于数据结构的栈。

2.堆区(heap):一般是由程序员分配释放,若程序员不释放的话,程序结束时可能由OS回收,值得注意的是他与数据结构的堆是两回事,分配方式倒是类似于数据结构的链表。

3.堆和栈的区别:

(1)由以上综述就可以得知,他们程序的内存分配方式不同。

(2)申请和响应不同:

(1)申请方式:

栈:由系统自动分配,系统收回;

堆:需要程序员自己申请,C语言中用函数malloc分配空间,用free释放。

(2)申请后系统的响应:

栈:只要栈的剩余空间大于所申请的空间,体统将为程序提供内存,否则将报异常提示栈溢出。

堆:首先应该知道操作系统有一个记录内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间

大于所申请的空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。另外,对于大多

数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的delete或free语句就能够正确的释放本

内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会将多余的那部分重新放入空闲链表中。

(3)申请的大小限制不同:

栈:在windows下,栈是向低地址扩展的数据结构,是一块连续的内存区域,栈顶的地址和栈的最大容量是系统预先规定好的,能从栈获得的空间较小。

堆:堆是向高地址扩展的数据结构,是不连续的内存区域,这是由于系统是由链表在存储空闲内存地址,自然堆就是

不连续的内存区域,且链表的遍历也是从低地址向高地址遍历的,堆得大小受限于计算机系统的有效虚拟内存空间,

由此空间,堆获得的空间比较灵活,也比较大。

(4)申请的效率不同:

栈:栈由系统自动分配,速度快,但是程序员无法控制。

堆:堆是有程序员自己分配,速度较慢,容易产生碎片,不过用起来方便。

(5)堆和栈的存储内容不同:

栈:在函数调用时,第一个进栈的是主函数中函数调用后的下一条指令的地址,然后是函数的各个参数,在大多数的

C编译器中,参数是从右往左入栈的,当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最

开始存的地址,也就是主函数中的下一条指令。

堆:一般是在堆得头部用一个字节存放堆得大小,具体内容由程序员安排。

作者:Mormont
来源:CSDN
原文:https://blog.csdn.net/mormont/article/details/53511441
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值