程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> 從關於素數的算法題來學習如何提高代碼效率

從關於素數的算法題來學習如何提高代碼效率

編輯:關於C
素數   在世博園某信息通信館中,游客可利用手機等終端參與互動小游戲,與虛擬人物Kr. Kong 進行猜數比賽。   當屏幕出現一個整數X時,若你能比Kr. Kong更快的發出最接近它的素數答案,你將會獲得一個意想不到的禮物。       例如:當屏幕出現22時,你的回答應是23;當屏幕出現8時,你的回答應是7;   若X本身是素數,則回答X;若最接近X的素數有兩個時,則回答大於它的素數。       輸入:第一行:N 要競猜的整數個數   接下來有N行,每行有一個正整數X   輸出:輸出有N行,每行是對應X的最接近它的素數       樣例:輸入   4   22   5   18   8   輸出   23   5   19   7       看到這個算法題我們首先要做的就是實現一個函數,來求出一個數是否是質數。下面我們來簡單的實現一下:   復制代碼 bool isPrime(int num) {     if(num < 2) return false;     for(int i=2; i*i<num; ++i){         if(num % i == 0) return false;     }     return true; } 復制代碼   由於這個函數在算法中會多次用到,我們用下面的測試來查看這個基本函數的效率   復制代碼 void test(){     clock_t start = clock();     for(int i=1; i <= 100000; ++i){         isPrime(1000000007);     }     clock_t end = clock();     cout << endl << static_cast<double>(end - start)/CLOCKS_PER_SEC << endl; } 復制代碼 運行,得到結果12.158   因為期間我們可能會進行重復的計算,對這個問題我一開始想到的解決方法就是建立一個質數表,我們可以直接通過查找表來快速的確定一個數是否是質數。當要判斷的數很大時,需要占用很大的空間來建表,為了節約空間,我將每一位都充分用上了。   復制代碼 #define GETNUM(x) psum[((x)>>3)]&(1<<(((x)&7)-1)) #define SETNUM(x) psum[((x)>>3)] &= (~(1<<(((x)&7)-1))) bool isPrime(int num) {     if(num < 2) return false;     int size = (num>>3)+1;     unsigned char *psum = new unsigned char[size];     memset(psum, 0xFF, size);     for(int i=2; i*i<num; ++i){         if(GETNUM(i)){             for(int j=i<<1; j<=num; j+=i){                 SETNUM(j);             }         }     }     bool result = GETNUM(num);     delete [] psum;     return result; } 復制代碼   因為質數表建立起來以後,之後的判斷直接取值就行了,所以我們就不做循環了,直接看它運行一次的時間,竟然用了29.853!耗時太長了,建這個表的時間可以進行20萬次試除法判斷了。   在經過一定的分析後,我將這個過程進行了一下優化   復制代碼 #define GETNUM(x) psum[((x)>>3)]&(1<<(((x)&7)-1)) #define SETNUM(x) psum[((x)>>3)] &= (~(1<<(((x)&7)-1))) bool isPrime2(int num) {     if(num < 2) return false;     int size = (num>>3)+1;     unsigned char *psum = new unsigned char[size];     memset(psum, 0xFF, size);     for(int j=4; j<num; j+=2){         SETNUM(j);     }     for(int i=3; i*i<num; ++i){         if(GETNUM(i)){             int step = i<<1;             for(int j=i*i; j<=num; j+=step){                 SETNUM(j);             }         }     }       bool result = GETNUM(num);     delete [] psum;     return result; } 復制代碼 上面的優化,我先是直接將2的倍數都淘汰掉,接著,基於在進行i的倍數判斷時,所有i的i-1以下的倍數都已經被淘汰掉了這一點,直接從i的平方開始淘汰,而且基於偶數倍能被2整除這一點,將步長調整為i*2.   經過優化,時間縮短為16.429,可是這個結果明顯是不能讓人滿意滴。。。   這時我參看了一下博文一個超復雜的間接遞歸——C語言初學者代碼中的常見錯誤與瑕疵(6),發現只是計算部分質數表,再利用質數表來加快質數的試除法這個方案很有可行性,於是趕緊行動。先進行預算,再進行試除法判斷質數。    View Code   改進的結果是令人振奮滴,時間縮短為0.021.   解決了素數判斷問題,得到想要的算法就很容易了   復制代碼 void precalc(int size, int * primes, int &pnum) {     bool *psum = new bool[size+1];     for(int j=4; j<=size; j+=2){         psum[j] = false;     }     memset(primes, 0, size * sizeof(int));     primes[0] = 2;     pnum = 1;     int i=3;     for(; i*i<=size; ++i){         if(psum[i]){             primes[pnum] = i;             ++pnum;             int step = i<<1;             for(int j=i*i; j<=size; j+=step){                 psum[j] = false;             }         }     }     for(;i<=size; ++i){         if(psum[i]){             primes[pnum] = i;             ++pnum;         }     }     delete [] psum; } bool isPrime5(int num, const int * primes, int pnum) {     for(int i=0; i<pnum && primes[i]*primes[i] < num; ++i){         if(num % primes[i] == 0) return false;     }     return true; } int get_nearest(int num, const int * primes, int pnum) {     if(isPrime5(num, primes, pnum)) return num;     int len;     if(num % 2 == 0){         len = 1;     }     else{         len = 2;     }     while(true){         if(isPrime5(num+len, primes, pnum)) return num + len;         if(isPrime5(num-len, primes, pnum)) return num - len;         len += 2;     } }    int _tmain(int argc, _TCHAR* argv[]) {     cout<<"請輸入數據"<<endl;     int count;     cin>>count;     int *data = new int[count];     //最大的一個數     int maxnum = 0;     for(int i=0; i<count; i++){         cin>>data[i];         if(maxnum < data[i]){             maxnum = data[i];         }     }     int size = static_cast<int>(sqrt(static_cast<double>(maxnum)));     int *primes = new int[size];     int pnum;     precalc(size, primes, pnum);     for(int i=0; i<count; i++){         cout<<get_nearest(data[i], primes, pnum)<<endl;     }     delete [] primes;     delete [] data;     cin.get();     return 0; }          
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved