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

歡迎訪問 生活随笔!

生活随笔

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

c/c++

堆排序 C++代码实现及思想 排序过程输出 恋上数据结构笔记

發布時間:2025/3/20 c/c++ 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 堆排序 C++代码实现及思想 排序过程输出 恋上数据结构笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

復習梗概

文章目錄

    • 復習梗概
    • 什么是堆思想?
    • 堆排序算法怎么來的?
    • 什么是下濾?代碼
    • 什么是建堆?代碼
    • 堆排序本體 代碼及排序過程輸出 和時間復雜度
    • 完整代碼

什么是堆思想?

  • 最大堆:樹形結構,每一個結點元素都比子結點大
  • 堆常常用動態數組存儲
  • 二叉最大堆能夠應用于動態數組,是因為應用了完全二叉樹的兩個特性:i為當前結點序號,左子結點 = 2i+1,右子結點=2i+2,父結點=floor((i-1)/2),這個是根結點序號為0的情況,這個特質不用死記硬背,想用的時候畫個圖自己標下序號就試出來了
  • 完全二叉樹,共n個結點,葉子結點序號從n/2開始(根結點為0)
  • 堆常常用來解決求數組里的最大值,最小值問題(Top K)
  • 堆的筆記 戀上數據結構

  • 堆排序算法怎么來的?

    選擇排序算法優化來的

    相比冒泡排序,選擇排序無法在內循環過程中,通過比較確定前面是否已經形成有序序列,因此我認為這里難以優化
    但實際上可以從另一個地方優化:即選取未排序序列最大值這個過程,如果用堆完成的話,時間復雜度只有O(logn)(主要是下濾,結點的高度logn),整體復雜度O(nlogn)
    因此,優化后的選擇排序算法 即為 堆排序


    什么是下濾?代碼

  • 為了確保堆的特性
  • 使不符合堆的特性的某個元素與其子結點元素比較,若子結點元素較大,則交換二者,更新二者索引,不斷重復與子結點比較,直到沒有子結點或已經比子結點大
  • 這里如何處理只有左子結點的結點?看代碼
  • void siftDown(vector<int> &array, int index, int end) {//! 這里指對array的index元素進行下濾操作,這里的end指的是未排序的序列的末尾元素的index,因為vector容器的size是私有的不能改int biggerChildIndex = index * 2 + 1;while (biggerChildIndex <= end){if (biggerChildIndex + 1 <= end && array[biggerChildIndex] < array[biggerChildIndex + 1]){ // if確保若該結點存在右子結點,且右結點值大于左結點,則biggerChildIndex更新為右結點的index//若沒有右子結點,該語句不會觸發,且biggerChildIndex默認就是左子結點,妙啊biggerChildIndex++;}if (array[index] < array[biggerChildIndex]){int temp = array[index];array[index] = array[biggerChildIndex]; //發現子結點大于該結點,進行調換array[biggerChildIndex] = temp;index = biggerChildIndex;biggerChildIndex = index * 2 + 1; //若發生下濾,則更新index和childIndex,進行下一次下濾比較}else{break; //若子結點大于該結點,停止本次下濾}} }

    什么是建堆?代碼

  • 用一段數組作為輸入
  • 建成一個堆(即符合堆特性的數組)
  • 具體過程可以由上至下每個結點上濾,也可以由下至上(從非葉子結點開始)每個結點下濾,后者效率較高,詳情見戀上數據結構二叉堆筆記
  • void BuildHeap(vector<int> &array) {int index = array.size() / 2 - 1; //這里是找到二叉堆的最后一個非葉子結點的位置,葉子結點不用下濾for (int i = index; i >= 0; i--){siftDown(array, i, array.size()); //從最后一個非葉子結點開始向上下濾(是建堆的兩種方法之一)} }

    堆排序本體 代碼及排序過程輸出 和時間復雜度

  • siftDown的位置?
  • BuildHeap的位置?
  • end控制的是什么??
  • 時間復雜度如下(圖出自戀上數據結構與算法-騰訊課堂-李明杰老師-第二季試聽第一節課)
  • void HeapSort(vector<int> &array) {BuildHeap(array);//! 對數組進行建堆后,array【0】就是該數組的最大值for (int end = array.size() - 1; end > 0; end--){siftDown(array, 0, end);//這里代表把0下濾,因為經過調換只有它不符合堆的特性,同時堆的末尾更新為end,在后面就是已經排好的有序序列了//這里下濾要放在循環內第一句,若放在調換后的話,因為end沒--,就把最大值下濾回去了int temp = array[0];array[0] = array[end];array[end] = temp;//! 此時array【0】是原本隊尾的小元素,對其進行下濾,使這個堆的array【0】依舊是最大} } 輸入數組: 6 9 3 1 2 0 8 29 15 11 10 堆排序基礎版 29 15 8 9 11 0 3 1 6 2 10 10 15 8 9 11 0 3 1 6 2 29 2 11 8 9 10 0 3 1 6 15 29 6 10 8 9 2 0 3 1 11 15 29 1 9 8 6 2 0 3 10 11 15 29 3 6 8 1 2 0 9 10 11 15 29 0 6 3 1 2 8 9 10 11 15 29 0 2 3 1 6 8 9 10 11 15 29 1 2 0 3 6 8 9 10 11 15 29 0 1 2 3 6 8 9 10 11 15 29 0 1 2 3 6 8 9 10 11 15 29 算法用時:(微秒) [AlgoTime: 11802 us] 排序完成: 0 1 2 3 6 8 9 10 11 15 29

    完整代碼

    #include <iostream> #include <vector> #include "MeasureAlgoTime.hpp" using namespace std;//! 選擇排序:從未排序序列中,找出最大的那個元素,與未排序序列的末尾元素交換, //! 不斷執行上述步驟(n-1輪),末尾最大元素形成有序序列(挑最小的也可以,看需求是升序還是降序) //! 最好最壞平均時間復雜度:O(n2) 空間復雜度:O(1) 屬于穩定排序 //! 相比冒泡排序,選擇排序無法在內循環過程中,通過比較確定前面是否已經形成有序序列,因此我認為這里難以優化 //! 但實際上可以從另一個地方優化:即選取未排序序列最大值這個過程,如果用堆完成的話,時間復雜度只有O(logn)(主要是下濾),整體復雜度O(nlogn) //! 因此,優化后的選擇排序算法 即為 堆排序void vectorPrint(vector<int> &array) {for (int i = 0; i < array.size(); i++){cout << array[i] << ' ';}cout << endl; }//堆的下濾函數 void siftDown(vector<int> &array, int index, int end) {//! 這里指對array的index元素進行下濾操作,這里的end指的是未排序的序列的末尾元素的index,因為vector容器的size是私有的不能改int biggerChildIndex = index * 2 + 1;while (biggerChildIndex <= end){if (biggerChildIndex + 1 <= end && array[biggerChildIndex] < array[biggerChildIndex + 1]){ // if確保若該結點存在右子結點,且右結點值大于左結點,則biggerChildIndex更新為右結點的index//若沒有右子結點,該語句不會觸發,且biggerChildIndex默認就是左子結點,妙啊biggerChildIndex++;}if (array[index] < array[biggerChildIndex]){int temp = array[index];array[index] = array[biggerChildIndex]; //發現子結點大于該結點,進行調換array[biggerChildIndex] = temp;index = biggerChildIndex;biggerChildIndex = index * 2 + 1; //若發生下濾,則更新index和childIndex,進行下一次下濾比較}else{break; //若子結點大于該結點,停止本次下濾}} }//利用已有的數組建立一個堆,實際上就是對數組里的元素進行排序(從下至上的下濾),使之符合堆的定義(每一個結點大于左右子結點) void BuildHeap(vector<int> &array) {int index = array.size() / 2 - 1; //這里是找到二叉堆的最后一個非葉子結點的位置,葉子結點不用下濾for (int i = index; i >= 0; i--){siftDown(array, i, array.size()); //從最后一個非葉子結點開始向上下濾(是建堆的兩種方法之一)} }void HeapSort(vector<int> &array) {BuildHeap(array);//! 對數組進行建堆后,array【0】就是該數組的最大值for (int end = array.size() - 1; end > 0; end--){vectorPrint(array);siftDown(array, 0, end);int temp = array[0];array[0] = array[end];array[end] = temp;//! 此時array【0】是原本隊尾的小元素,對其進行下濾,使這個堆的array【0】依舊是最大}vectorPrint(array); }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;cout<<"輸入數組:"<<endl;time1.start();vectorPrint(array);cout << "堆排序基礎版" << endl;HeapSort(array);cout << "算法用時:(微秒)";time1.printElapsed();cout<<"排序完成:"<<endl;vectorPrint(array);return 0; }

    總結

    以上是生活随笔為你收集整理的堆排序 C++代码实现及思想 排序过程输出 恋上数据结构笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

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