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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

快速排序 C++代码实现及其算法思想及时间复杂度分析及优化 恋上数据结构笔记

發布時間:2025/3/20 c/c++ 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 快速排序 C++代码实现及其算法思想及时间复杂度分析及优化 恋上数据结构笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 復習梗概
    • 算法思想
    • 算法復雜度分析及穩定性
    • 如何優化?
    • 快速排序改進版代碼C++
    • 快速排序個人青春版代碼
    • 完整代碼

復習梗概

  • 算法思想,別的排序名字直接就能讓人聯想到它的算法思想,唯獨快速排序這個不能直接體現出算法思想,因為它太麻煩了
  • 圖解腦圖
  • 代碼結構眼熟(算法學完思想不能忘,但是轉換成代碼容易忘,最方便的方式是記住代碼的大概結構,比如循環,遞歸,判斷這些,以及條件和他們的結構順序,不是說這就是背代碼,但這樣確實有助于考場上一眼認出來相似的算法題,就是眼熟)
  • 最好時間復雜度與最壞時間復雜度取決于什么因素??
  • 分析時間復雜度的方法
  • 為什么相等元素時也要調換位置,是為了什么??
  • 優化方法有什么,從哪里入手?
  • 有幾個函數組成?彼此作用是什么,結構是什么?

  • 算法思想

  • 一句話概括:逐漸將所有元素都轉換為軸點元素
  • 軸點:天選之點,比這個元素大的都要排在右邊,小的都要排在左邊
  • 細說步驟開始:首先選數組第一個元素為軸點,temp暫時保存軸點值
  • 定義begin和end指針,指向這段數組起點和終點,begin初始就是指向軸點的
  • 從end開始向左比較元素與軸點大小,比軸點大就不動,end–接著比; 小就直接轉換到begin覆蓋此時的begin位置元素(第一次覆蓋的是軸點,我們已經保存了,不怕),begin++后移,然后下一次比較從begin開始
  • 從begin開始向右比較元素與軸點大小,比軸點小就不動,begin++接著比; 大就直接轉換到end覆蓋此時的end位置元素(此時end所指元素以及轉換到begin之前的位置了,不怕),end–前移,然后下一次比較從end開始
  • 整體概括就是begin和end雙向奔赴互相給對面找位置轉換,符合右邊比軸點大左邊比軸點小的原則,最后相遇找到軸點位置的過程
  • 上述步驟循環
  • begin和end相遇結束循環,記錄此時位置為軸點位置,用軸點覆蓋(由于上述步驟,此時begin和end相遇位置一定是下一個被覆蓋的值,不怕)
  • 數組以軸點位置分為兩段 ,分別再來一次上述步驟(遞歸)

  • 流程圖來自騰訊網課,戀上數據結構與算法,李明杰老師


    算法復雜度分析及穩定性

  • 快速排序不穩定,怎么優化都沒用
  • 影響快速排序的時間復雜度的因素:每次分割左右子序列是否平均!
  • 快速排序最好(平均)時間復雜度:O(nlogn)
  • 在最好情況下,每次分割左右子序列都是平均分割那么
  • //算法時間復雜度分析,假如最開始的這個quiksout耗時T(n) void quikSort(vector<int> &array,int begin,int end){int pivotIndex = SearchAndSort(array,begin,end);上面語句中函數時間復雜度為O(n),因為尋找軸點和排序這個函數 過程就是遍歷一邊數組quikSort(array,begin,pivotIndex-1);因為平均分割,上面這個quiksort函數耗時就是T(n/2quikSort(array,pivotIndex+1,end);因為平均分割,上面這個quiksort函數耗時就是T(n/2}
  • 經過上面的函數語句時間分析得到下面的等式
  • 經過數學手法得到最終時間復雜度為O(nlogn)
  • 同理,最壞時間復雜度為O(n2),比如數組每次軸點元素都是數組的最大值或最小值,導致每次分子序列都是1和n-1個
  • //算法時間復雜度分析,假如最開始的這個quiksout耗時T(n) void quikSort(vector<int> &array,int begin,int end){int pivotIndex = SearchAndSort(array,begin,end);上面語句中函數時間復雜度為O(n),因為尋找軸點和排序這個函數 過程就是遍歷一邊數組quikSort(array,begin,pivotIndex-1);因為不平均分割,子序列里沒有元素直接返回,上面這個quiksort函數耗時就是T(1),可以忽略不計quikSort(array,pivotIndex+1,end);因為不平均分割,子序列里有除了首位軸點元素以外的所有元素,上面這個quiksort函數耗時就是T(n-1),以后就是n-2,n-3.。。到1,就是等差數列公式了 }

  • 空間復雜度:O(logn),應該與遞歸調用和系統棧有關系,以后會學

  • 如何優化?

  • 看了上面的時間復雜度分析,我們自然想到,優化就要從減少分割不平均的情況入手
  • 第一種優化方式:選擇軸點過程不再是固定選擇首位,而是隨機選擇,這樣可以減少選到序列里最大或最小值作為軸點的情況,進而減少不平均分割
  • 第二種優化方式:當有元素與軸點元素相等時,也要進行轉換覆蓋,想象一下如果不進行,一個全是相同元素的數組進行快速排序,無疑是最壞級別的,所以這樣可以促進兩個子序列的平均,避免不平均
  • 可惜上面兩種優化,都不能優化其不穩定的特征

  • 快速排序改進版代碼C++

    自己復刻的老師版本,代碼結構尤其后面遞歸要眼熟
    主要優化了代碼結構,和循環那里

    int SearchAndSort(vector<int> &array, int begin, int end) {int pivotNum = array[begin];//思路是end--直到發生覆蓋,然后進行begin++直到發生覆蓋,又回到end--如此反復//很多時候兩個if嵌套都可以改進成whilewhile (begin<end){while(begin<end){if(array[end]>pivotNum){//右側值大于軸點值,不需要改動位置(覆蓋begin當前元素),end--end--;}else{//右側值小于軸點值array[begin] = array[end];begin++;break;//break只會打破一層循環,此時發生了覆蓋,要掉頭了}}while (begin<end){if(array[begin]<pivotNum){begin++;}else{array[end] = array[begin];end--;break;}}}array[end] = pivotNum;return end; //注意這里要返回end,因為判斷元素是end-begin+1而begin有時存在-1的情況,會負負得正,而end即使是負的也不怕 }void quikSort2nd(vector<int> &array,int begin,int end){if((end - begin +1)<2){return;}int pivotIndex = SearchAndSort(array,begin,end);//注意這里除了array都是值傳遞,不會影響主函數的begin和end值的,所以大可放心vectorPrint(array);quikSort2nd(array,begin,pivotIndex-1);quikSort2nd(array,pivotIndex+1,end); } 6 9 3 1 2 0 8 29 15 11 10 快速排序改進版 0 2 3 1 6 9 8 29 15 11 10 0 2 3 1 6 9 8 29 15 11 10 0 1 2 3 6 9 8 29 15 11 10 0 1 2 3 6 8 9 29 15 11 10 0 1 2 3 6 8 9 10 15 11 29 0 1 2 3 6 8 9 10 15 11 29 0 1 2 3 6 8 9 10 11 15 29 算法用時:(微秒) [AlgoTime: 20004 us]

    快速排序個人青春版代碼

    自己寫的,獻給年輕的自己

    //快速排序:其實比較難想,整體概括就是begin和end雙向奔赴互相給對面找位置,最后找到軸點位置的過程//自己看完思路寫的快速排序,其實大體上和老師寫的差不多,就是都寫到一個里了,但是排查bug排查了兩個小時都沒找出問題出在哪 void quikSort(vector<int> &array, int begin, int end) {//沒想到這個東西惡心了我兩小時,end和begin分別代表數組頭元素和尾元素下標//那么begin到end的元素數量就是end-begin+1而不是-1啊啊啊,這都能整錯if ((end - begin + 1) < 2){return;}int tempBegin = begin;//臨時存儲begin的值,因為后面begin會變,我們還需要它代表下一個遞歸左數組的起點呢int tempEnd = end;//同上int pivot = array[begin];//臨時存儲軸點值,因為后面軸點這個位置會被覆蓋int beginOrEnd = 1;//記錄上次循環是end--了還是begin++了while (begin != end){if (beginOrEnd == 1)//如果上次循環動的是end--,或者第一次,那這次就從end開始//以end--為例子,end--有兩種情況,一種array[end] > pivot不用動,接著比較,一種array[begin] > pivot,把當前end元素覆蓋了,end--{if (array[end] < pivot)//第一次從end開始{array[begin] = array[end];begin++;beginOrEnd = 0;}else{end--;beginOrEnd = 1;}}else{if (array[begin] > pivot){array[end] = array[begin];end--;beginOrEnd = 1;}else{begin++;beginOrEnd = 0;}}}array[begin] = pivot;//把軸點值放到合適位置vectorPrint(array);quikSort(array, tempBegin, end - 1);quikSort(array, end + 1, tempEnd); } 6 9 3 1 2 0 8 29 15 11 10 快速排序基礎版 0 2 3 1 6 9 8 29 15 11 10 0 2 3 1 6 9 8 29 15 11 10 0 1 2 3 6 9 8 29 15 11 10 0 1 2 3 6 8 9 29 15 11 10 0 1 2 3 6 8 9 10 15 11 29 0 1 2 3 6 8 9 10 15 11 29 0 1 2 3 6 8 9 10 11 15 29 算法用時:(微秒) [AlgoTime: 20005 us]

    完整代碼

    #include <iostream> #include <vector> #include "MeasureAlgoTime.hpp" using namespace std;void vectorPrint(vector<int> &array) {for (int i = 0; i < array.size(); i++){cout << array[i] << ' ';}cout << endl; } //快速排序:其實比較難想,整體概括就是begin和end雙向奔赴互相給對面找位置,最后找到軸點位置的過程//自己看完思路寫的快速排序,其實大體上和老師寫的差不多,就是都寫到一個里了,但是排查bug排查了兩個小時都沒找出問題出在哪 void quikSort(vector<int> &array, int begin, int end) {//沒想到這個東西惡心了我兩小時,end和begin分別代表數組頭元素和尾元素下標//那么begin到end的元素數量就是end-begin+1而不是-1啊啊啊,這都能整錯if ((end - begin + 1) < 2){return;}int tempBegin = begin;//臨時存儲begin的值,因為后面begin會變,我們還需要它代表下一個遞歸左數組的起點呢int tempEnd = end;//同上int pivot = array[begin];//臨時存儲軸點值,因為后面軸點這個位置會被覆蓋int beginOrEnd = 1;//記錄上次循環是end--了還是begin++了while (begin != end){if (beginOrEnd == 1)//如果上次循環動的是end--,或者第一次,那這次就從end開始//以end--為例子,end--有兩種情況,一種array[end] > pivot不用動,接著比較,一種array[begin] > pivot,把當前end元素覆蓋了,end--{if (array[end] < pivot)//第一次從end開始{array[begin] = array[end];begin++;beginOrEnd = 0;}else{end--;beginOrEnd = 1;}}else{if (array[begin] > pivot){array[end] = array[begin];end--;beginOrEnd = 1;}else{begin++;beginOrEnd = 0;}}}array[begin] = pivot;//把軸點值放到合適位置vectorPrint(array);quikSort(array, tempBegin, end - 1);quikSort(array, end + 1, tempEnd); }int SearchAndSort(vector<int> &array, int begin, int end) {int pivotNum = array[begin];//思路是end--直到發生覆蓋,然后進行begin++直到發生覆蓋,又回到end--如此反復//很多時候兩個if嵌套都可以改進成whilewhile (begin<end){while(begin<end){if(array[end]>pivotNum){//右側值大于軸點值,不需要改動位置(覆蓋begin當前元素),end--end--;}else{//右側值小于軸點值array[begin] = array[end];begin++;break;//break只會打破一層循環,此時發生了覆蓋,要掉頭了}}while (begin<end){if(array[begin]<pivotNum){begin++;}else{array[end] = array[begin];end--;break;}}}array[end] = pivotNum;return end; //注意這里要返回end,因為判斷元素是end-begin+1而begin有時存在-1的情況,會負負得正,而end即使是負的也不怕 }void quikSort2nd(vector<int> &array,int begin,int end){if((end - begin +1)<2){return;}int pivotIndex = SearchAndSort(array,begin,end);//注意這里除了array都是值傳遞,不會影響主函數的begin和end值的,所以大可放心vectorPrint(array);quikSort2nd(array,begin,pivotIndex-1);quikSort2nd(array,pivotIndex+1,end); }int main() {Tools::Time::AlgoTimeUs time1;Tools::Time::AlgoTimeUs time2;Tools::Time::AlgoTimeUs time3;vector<int> array;array = {6, 9, 3, 1, 2, 0, 8, 29, 15, 11, 10};vector<int> array2 = array;vector<int> array3 = array;time1.start();vectorPrint(array);cout << "快速排序基礎版" << endl;quikSort(array, 0, (array.size() - 1));cout << "算法用時:(微秒)";time1.printElapsed();cout << ' ' << endl;time1.start();vectorPrint(array2);cout << "快速排序改進版" << endl;quikSort2nd(array2, 0, (array.size() - 1));cout << "算法用時:(微秒)";time1.printElapsed();cout << ' ' << endl;return 0; }

    總結

    以上是生活随笔為你收集整理的快速排序 C++代码实现及其算法思想及时间复杂度分析及优化 恋上数据结构笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

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