C++ 由快排學習到的的隨機數等知識

来源:https://www.cnblogs.com/xhzg/archive/2022/09/07/16630883.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 最近在研究一個基於TP6的框架CRMEB,這裡分享下我的開發心得 首先要獲取原始項目文件 這裡是git地址 https://gitee.com/ZhongBangKeJi/CRMEB.git 項目環境的要求為Apache、MySQL、PH ...


  • 起:

力扣的912題 數組排序 ,想著先用快速排序來寫寫,在實際用c++編寫的時候,有一些之前沒註意到的細節問題造成了一些麻煩。

912. 排序數組 - 力扣(LeetCode)

 

 

 

  • 快排思想

  每次以數組最後一個數為基準,按照波蘭國旗問題對數組進行分層(partition)。假設最後一個數為P,則將數組分為小於P、等於P、大於P的3層。之後對小於P和大於P的層進行此過程的迭代。迭代完成後,目標數組即排列完成。

  1.   問題:最壞的結果的O(n^2),因為每次最後一個數當成分層基準,最壞的情況是左右兩層極度不平衡
  2.   改進:引入隨機數,每次進行分層之前,隨機將數組前面的一個數與最後一個數P進行swap,這樣分層就成了一個隨機事件。在數學證明中,可證明時間複雜度收斂於0(N*LogN)。
  • C++中的隨機數

  在c++中,獲取隨機數一般廣為人知的方法是 rand() ,但是這種方法獲得的隨機數是偽隨機數,其原理是從一個已經確定了的序列中按順序返回整數。

  在直接使用 rand()時,預設的 srand(1)。srand可以認為是種子。

    只使用rand()時

int main() {
    for (int i = 0; i < 10; i++) {
        cout << rand() << "\t";
    }
    return 0;
}

  輸出結果(因電腦而異):

    41      18467   6334    26500   19169   15724   11478   29358   26962   24464

  你每次運行,答案和該結果都一致,這是因為種子沒變,永遠輸出的是該序列前十個數字。

  所以有一個思路就是改變種子,想讓每次運行的種子發生變化,那麼就想到了時間,時間是每秒都在變化的,可以讓時間來充當種子參數

  

int main() {
    srand((int)time(NULL)); // #include<ctime> for time()
    for (int i = 0; i < 10; i++) {
        cout << rand() << "\t";
    }
    return 0;
}

  輸出結果:

    31937   9951    11817   1295    252     30339   22649   12202   9420    16246

  與之前結果不同了。似乎這達到了我們獲取真隨機數的目的。但是依舊有一個問題,那就是time 是以秒為單位的,如果你的項目要在一秒之內調用多次隨機數呢?這樣一來,種子在這一秒之內是不會發生變化的。

int getrd_1() {
    srand((int)time(NULL)); // #include<ctime> for time()
    return rand();
}

int main() {
    for (int i = 0; i < 10; i++) {
        cout << getrd_1() << "\t";
    }
    return 0;
}

   輸出結果:

      32753   32753   32753   32753   32753   32753   32753   32753   32753   32753

    果然是一樣的,因為這十次調用都是在1秒之內。

    這種情況下,可以使用random_device 來生成真隨機數

    

int getrd(const int &min, const int&max) {//範圍 [min,max)
    std::random_device rd;                //#include<random> for std::random_device
    return min + rd() % max;
}
int main() {
    for (int i = 0; i < 10; i++)
        std::cout << getrd(0, 10) << "\t";
    return 0;
}

    輸出結果:

        3       0       0       9       7       8       5       4       9       2

    達到了我們預期的要求。

    但是,需要註意,這個實現要看你的庫支持不支持,如果不支持,將繼續使用偽隨機數發生器。可以通過調用random_device的成員函數 entropy()來查看熵,如果是偽隨機發生器,熵恆為零

  • swap

    

//通過一個臨時變數來儲存b的值,完成交換
void swap(int &a, int &b) {
    int tmp(b);
    b = a;
    a = tmp;
}
//通過異或^來完成交換
void swap(int &a, int &b) {
    if (a == b)
        return;
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}

    第一種交換司空見慣了,第二種則用到了位操作 異或 ^ 的性質:

            a ^ 0 等於 a                           a ^ a 等於 0 

            滿足結合律,交換律

    因此:

        第一句:a = a ^ b ;   第二句:b = a ^ b,此時 b 等於 a^b^b,結合性質 結果是 a  ; 第三句 : a = a ^ b ,此時 a等於 a ^ b ^ a,結果是b ,交換完成

    需要註意的是,如果a 與  b 的地址相同 則 a^b 等於0。

最後貼上我的快排:

 

class Solution {
private:
    void swap(int& a, int& b) {
        if (a == b)
            return;
        a = a ^ b;
        b = a ^ b;
        a = a ^ b;
    }
    int getrd(const int &min,const int& max) {
        random_device rd;
        return min + rd() % (max - min);
    }
public:
    //快排
    int* Mypartition(vector<int>& nums, int L, int R) {
        int less(L - 1), more(R);
        int i(L);
        while (i < more) {
            if (nums[i] < nums[R]) {
                swap(nums[++less], nums[i++]);
            }
            else if (nums[i] > nums[R]) {
                swap(nums[i], nums[--more]);
            }
            else
                i++;
        }
        swap(nums[more], nums[R]);
        return new int [2]{ less, more+1 };
    }
    void process(vector<int>& nums, int L, int R) {
        if (L < R) {
            // cout<<"L ="<<L<<"\t R="<<R<<endl;
            swap(nums[getrd(L,R)], nums[R]);
            int *p = Mypartition(nums,L,R);
            process(nums, L, p[0]);
            process(nums, p[1], R);
        }
    }
    vector<int> sortArray(vector<int>& nums) {
        process(nums, 0, nums.size()-1);
        return nums;
    }
};

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原型模式(Prototype Pattern)是用於創建重覆的對象,同時又能保證性能。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。 ...
  • Python自學第六天:實戰練習——機選雙色球 我是一個編程小白,目前從事運維工作。 對於運維相關的技術,基本上都是瞭解點皮毛。 因為最近接觸自動化運維工具,看到很多工具都需要用到Python來寫腳本。 於是,利用業餘時間,開始自學Python。 目的並不是要學到很精通,而是希望大致看明白別人寫的代 ...
  • 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> OpenGL ES 特效 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> O ...
  • Qt中MVC的M(Model)簡單介紹 Qt有自己的MVC框架,分別是model(模型)、view(視圖)、delegate(委托),這篇文章,簡單的介紹以下Qt中有關model(模型)的類以及一些基本的使用。 Qt官方的文檔已經很詳細了,如果想要詳細的去瞭解,建議花點精力去看官方文檔。 @ 類繼承 ...
  • 說明 這是關於Qt5(Qt5.1.4.2),QWidget編程使用Qt虛擬鍵盤(qtvirtualkeyboard) Tag: QT5,Qt,軟體盤、虛擬鍵盤,Widget程式,QML 作者:[email protected] 關鍵代碼 啟用虛擬鍵盤模塊 在QApplication對象創建之前插入代碼 ...
  • JavaGUI-坦克大戰04 7.線程的應用03 7.3坦克大戰4.0版 7.3.4功能3:敵方坦克自由移動 功能3:讓敵人的坦克也可以自由隨機地上下左右移動 思路: 因為要求敵人的坦克自由移動,因此需要將敵人坦克當做線程使用,EnemyTank類實現Runnable介面 線程的run方法的具體操作 ...
  • JavaGUI-坦克大戰03-2 7.線程的應用02 7.3.坦克大戰4.0版 坦克大戰4.0版 增加功能: 功能1.讓敵人的坦克也能夠發射子彈(可以有多個子彈) 功能2.當我方坦克集中敵人坦克時,敵人的坦克就消失,如果能做出爆炸的效果更好 功能3.讓敵人的坦克也可以自由隨機地上下左右移動 功能4. ...
  • 1.什麼是模板層 模板層可以根據視圖中傳遞的字典數據動態生產相應的HTML頁面 2.模板層的配置 1.在項目下創建一個與同名文件夾平行的templates文件夾 2.在settings.py中的TEMPLATES配置項中 BACKEND:指定模板的引擎 DIRS:模板的搜索目錄(可以是一個或者多個) ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...