日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

质数问题

發布時間:2023/12/13 综合教程 25 生活家
生活随笔 收集整理的這篇文章主要介紹了 质数问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

打印質數的算法應該是學習計算機編程的一個經典的問題,在這里想給大家展示一些方法,相信這些方法會對你的編程有一定的啟發作用。請你注意幾點,

實際應用和教學應用有很大的差別。
最后的那個使用編譯時而不是運行時的方法大家可以重點看看。

教科書的示例

首先,先給一個教科書的示例。下面這個示例應該是教科書(至少是我上大學時的教科學)中算法復雜度最好的例子了。其想法很簡單,先寫一個判斷是否是質數的函數isPrime(),然后從1到n分別調用isPrime()函數來檢查。檢查是否是質數的算法是核心,其簡單的使用從2到n的開根的數作為除數。這樣的算法復雜度幾乎是O(n*log(n)),看上去不錯,但其實很不經濟。

#include <iostream>
using namespace std;
 
bool isPrime(int nr)
{
    for (int d = 2; (d * d) < (nr + 1); ++d){
        if (!(nr % d)){
            return false;
        }
     }
    return true;
}
 
int main (int argc, char * const argv[])
{
    for (int i = 0; i < 50; ++i){
        if (isPrime(i)){
            cout << i << endl;
        }
    }
}

較好的算法

我們知道,我們的算法如果寫成線性算法,也就是O(n),已經算是不錯了,但是最好的是O(Log(n))的算法,這是一個對數級的算法,著名的二分取中(Binary Search)正是O(Log(n))的算法。通常來說,O(Log(n))的算法都是以排除法做為手段的。所以,找質數的算法完全可以采用排除法的方式。如下所示,這種算法的復雜度是O(n(log(logn)))。

示例:打印30以內的質數

一、初始化如下列表。

 2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

二、把第一個數(2)取出來,去掉所有可以被2整除的數。

 2  3     5     7     9    11    13    15    17    19    21    23    25    27    29

三、取第二個數(3),去掉所有可以被 3整除的數。

 2  3     5     7          11    13          17    19          23    25          29

四、取第三個數(5),因為4已經被去除了,再去掉所有可以被5整除的數。

 2  3     5     7          11    13          17    19          23                29

接下來的數是7,但是7的平方是49,其大于了30,所以我們可以停止計算了。剩下的數就是所有的質數了。

實際應用的算法

實際應用中,我們通常不會使用上述的兩種算法,因為那是理論學院派的算法。實際中的算法是,我把質數事先就計算好,放在一個文件中,然后在程序啟動時(注意是在啟動時讀這個文件,而不是運行時每調用一次就讀一次文件),讀取這個文件,然后打印出來就可以了。如果需要查找的化,二分查找或是hash表查找將會獲得巨大的性能提升。當然,這樣的方法對于空間來說比前面兩個都要消耗得大,但是你可以有O(log(n))或是O(1)的時間復雜度。

所以,我想在這里提醒大家——實際和理論的的方法很不一樣的,千萬不要讀書讀成書呆子。在游戲編程的世界里,大量的數據都不是運行計算的,而都是寫在文件中的。比如,一個火焰效果,一個人物跑動的動作,都是事先寫在文件中的。

使用編譯時而不是運行時

下面這個例子(本例參考于這里)你需要注意了,這是一個高級用法,使用模式來在編譯時計算質數,而不是運行時。這種技術使用了C++編譯器對模板的特化時的處理來生成自己相要的結果。這種方法在技術上是相當Cool的,但并不一定實用,這里只是想像大家展示這種用法。這是C++的最骨灰級的用法了。

請看下面的兩個模板類,第一個模板以遞歸的方式檢查是否是質數,第二個方法是遞歸的退出條件(當N=1時),對于模板的重載,請參看相關的C++書籍。

template<int N, int D = N - 1>
struct isPrime {
    enum {
        result = (N % D) && isPrime<N, D-1>::result
    };
};
 
template<int N>
struct isPrime<N, 1> {
    enum {
        result = true
    };
};

于是,通過這個模板,我們可以使用下面的代碼來檢查是否是質數:

if (isPrime<3>::result)
    cout << "Guess what: 3 is a prime!";

下一步,我們需要打出一個區間內的質數,所以,我們需要繼續設計我們的print模板。

template<int N, bool ISPRIME>
struct printIfPrime {
    static inline void print() {}
};
 
template <int N>
struct printIfPrime<N, true> {
    static inline void print() {
        std::cout << N << endl;
    }
};

從上面的代碼中,我們可以看到,我們的第一個實際是什么也沒做,而第二個有輸出,注意第二個的模板參數中有一個true,其意味著那個質數的判斷。于是我們就可以給出下面的代碼來嘗試著打印出一段區間內的質數:(請不要編譯!!因為那會讓編譯器進入無限循環中,原因是printPrimes會不停地調用自己永不停止)

template<int N, int MAX>
struct printPrimes {
    static inline void print()
    {
        printIfPrime<N, isPrime<N>::result>::print();
        printPrimes<N + 1, MAX>::print();
    }
};

為了避免這個問題,你需要再加一個模板類,如下所示。這樣當N變成MAX的時候,遞歸就結束了。

template<int N>
struct printPrimes<N, N> {
    static inline void print() {
        printIfPrime<N, isPrime<N>::result>::print();
    }
};

最后,讓我們來看看最終的調用:

int main (int argc, char * const argv[])
{
    printPrimes<2, 40>::print();
    return 0;
}

這個方法很NB,但是有兩個問題:

比較耗編譯時間。
不能在運行時輸入MAX的值。

不過,相信這種玩法會啟動你很多的編程思路。

當然,還有以前說過的那個——《檢查素數的正則表達式》

(全文完)

【轉自】http://coolshell.cn/articles/3738.html

總結

以上是生活随笔為你收集整理的质数问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。