c、c++關於質數||素數的求法

大一剛剛結束,回過頭髮現自己這一年太浪了,基本沒學什麼東西,所以下定決心從頭開始

那就說一下這最簡單又不簡單的質數問題吧

我們要求某個範圍內的所有質數,當然最基本最重要的方法就是除一個數取餘數在判斷是否爲0

一、最簡單的粗暴的窮舉法

#include<iostream>
#include<math.h>
#include<time.h>

#define max 100

using namespace std;

void main() {

	clock_t start, end;

	start = clock();

	int * prime = (int*)malloc(sizeof(int)*max);//記錄所有素數的數組

	int count = 1;//素數的個數

	*prime = 2;//初值

	for (int i = 3; i <= max; ++i) {

		bool choice = true;//假設爲質數

		for (int j = 2; j <i; ++j) {

			if (i%j == 0) {//不是質數

				choice = false;

				break;
			}
		}

		if (choice) {

			*(prime + count) = i;

			count++;
		}
	}
	free(prime);//釋放素數的數組指針,避免內存泄漏

	end = clock();

	float time = (float)(end - start) / 1000;

	cout << "time is  " << time << "s" << endl;

	cout << "count is  " << count << endl;

	system("pause");
}


二、循環範圍由2~i-1變成2~sqrt(i)

至於爲什麼是sqrt(i)自己思考吧,數學問題

#include<iostream>
#include<math.h>
#include<time.h>

#define max 100

using namespace std;

void main() {

	clock_t start, end;

	start = clock();

	int * prime = (int*)malloc(sizeof(int)*max);//記錄所有素數的數組

	int count = 1;//素數的個數

	*prime = 2;//初值

	for (int i = 3; i <= max; ++i) {

		bool choice = true;//假設爲質數

		for (int j = 2; j <=sqrt(i); ++j) {

			if (i%j == 0) {//不是質數

				choice = false;

				break;
			}
		}

		if (choice) {

			*(prime + count) = i;

			count++;
		}
	}

	for (int i = 0; i < count; ++i) {
		cout << prime[i] << endl;
	}

	free(prime);//釋放素數的數組指針,避免內存泄漏

	end = clock();

	

	float time = (float)(end - start) / 1000;

	cout << "time is  " << time << "s" << endl;

	cout << "count is  " << count << endl;

	system("pause");
}



三、我們發現每次循環都調用sqrt函數比較慢,所以先把這個數賦給k,直接調用k就好了

#include<iostream>
#include<math.h>
#include<time.h>

#define max 10000000

using namespace std;

void main() {

	clock_t start, end;

	start = clock();
		
	int * prime = (int*)malloc(sizeof(int)*max);//記錄所有素數的數組

	int count = 1;//素數的個數

	*prime = 2;//初值

	for (int i = 3; i <= max; ++i) {

		bool choice = true;//假設爲質數

		int k = sqrt(i);

		for (int j = 2; j <= k ; ++j) {

			if (i%j == 0) {//不是質數

				choice = false;

				break;
			}
		}

		if (choice) {

			*(prime + count) = i;

			count++;
		}
	}
	free(prime);//釋放素數的數組指針,避免內存泄漏

	end = clock();

	float time = (float)(end - start)/1000;

	cout << "time is  " << time <<"s"<< endl;

	cout << "count is  " << count << endl;

	system("pause");
}



四、這步優化相對困難。我們知道,所有合數都能寫成若干素數相乘的形式,故判斷i數i是否爲質數,只需要用i除以從2到sqrt(i)之間的質數就可以,不需要除以這個區間的合數。但是問題出現了,我們要記錄所有小於i的質數,這就要用堆內存建立一個整型數組,數組長度爲max(我在考慮是不是可以建一個更小點的,,,算了,比較懶,不想了)用來保存所有已經求過的質數,這步的關鍵還有就是默認好2是第一個質數。


#include<iostream>
#include<math.h>
#include<time.h>


#define max 100000000


using namespace std;


void main() {


	clock_t start, end;


	start = clock();


	int * prime =(int*) malloc(sizeof(int)*max);//記錄所有素數的數組


	int count = 1;//素數的個數


	*prime = 2;//初值


	int tempmax = 0;//小於sqrt(i)的最大素數下標


	for (int i = 3; i <= max; ++i) {


		bool choice = true;//假設爲質數


		int k = sqrt(i) + 1;


		for (int j = 0; j <=tempmax; ++j) {


			if(prime[tempmax] < k)tempmax++;


			if (i % prime[j] == 0) {//不是質數


				choice = false;


				break;
			}
		}


		if (choice) {//是質數


			*(prime + count) = i;


			count++;
		}
	}
	//for (int i = 0; i < count; ++i) {
	//	cout << i<<"            "<<prime[i] << endl;
	//}
	free(prime);//釋放素數的數組指針,避免內存泄漏


	end = clock();


	float time = (float)(end - start) / 1000;
	
	cout << "time is  " << time << "s" << endl;


	cout << "count is  " << count << endl;


	system("pause");
}


這點東西做了一上午,哎,真是鹹魚。。。大二重新做人吧


關於速度的結果如下,可以看到每一步的優化是有效果的,而且在求較大範圍的質數時更加明顯


本文章可能存在很多不足,請多指點


2017 / 7 / 7

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章