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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

堆排序总结

發布時間:2024/4/14 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 堆排序总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

堆排序

概念:

    • 第一個非葉子節點: 小于size/2的部分;
    • 非葉子節點的區間: [0, size/2); (注意是左閉右開)
    • 最大堆:滿足父節點head, arr[head]<=arr[2*head+1] && arr[head]<=arr[2*head+2]
    • 非葉子節點的子樹才需要調整(沒有子節點的樹何談調整)?
      ps: 全文使用的下標均是從0開始

堆排序過程

  • 初始化堆: 從size/2到0調整堆, 使得堆滿足條件;
  • 調整堆:?
    如果head在非葉子節點的區間, 即head 屬于[0,size/2), 則需要檢查是否需要調整, 從head, 2head+1, 2head=2中選擇出最大值的下標; 如果maxnIndex!=head, 則需要進行交換swap(arr[head], arr[maxnIndex]), 然后在遞歸檢查以maxnIndex的子樹是否滿足堆的條件(因為在交換后, 子堆可能不滿足堆的條件), 檢查方式adjustHeap(arr,maxnIndex, size);
  • 堆排序: 從size-1到1, 逐個與arr[0]交換, 并且重新檢查堆(原來size)-1的堆是否滿足條件: adjustHeap(arr, 0, i);

堆排序代碼

1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 6 void adjustHeap(int arr[], int head, int size){ 7 8 // 如果頭節點是非葉子節點才需要進行調整 9 if(head<size/2){ 10 // 數組下標從0開始 11 int maxnIndex = head; 12 int left = 2 * head + 1; 13 int right = 2 * head + 2; 14 if(left<size && arr[left]>arr[maxnIndex]) 15 maxnIndex = left; 16 if(right<size && arr[right]>arr[maxnIndex]) 17 maxnIndex = right; 18 if(maxnIndex != head){ 19 swap(arr[head], arr[maxnIndex]); // 將最大值放在頭節點 20 adjustHeap(arr, maxnIndex, size); // 為了防止調整后的子樹不滿足堆的條件,需要遞歸調整 21 } 22 } 23 } 24 25 // 初始化堆 26 void buildHeap(int arr[], int size) { 27 //從第一個非葉子節點開始調整堆 28 for(int i=size/2;i>=0;i--){ 29 adjustHeap(arr, i, size); 30 } 31 } 32 33 void headSort(int arr[], int size) { 34 // 建堆 35 buildHeap(arr, size); 36 37 // 堆排序 38 for(int i=size-1;i>0; i--){ 39 swap(arr[0], arr[i]); 40 adjustHeap(arr, 0, i); 41 } 42 } 43 44 int main(){ 45 int arr[1000]; 46 int n; 47 while(cin>>n){ 48 for(int i=0;i<n;i++){ 49 cin >> arr[i]; 50 } 51 52 headSort(arr, n); 53 54 for(int i=0;i<n;i++){ 55 cout << arr[i] << " "; 56 }cout<<endl; 57 } 58 }

?

以下為原理分析部分

堆排序的思想

?

1.堆

??堆實際上是一棵完全二叉樹,其任何一非葉節點滿足性質:

? Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2]

? 即任何一非葉節點的關鍵字不大于或者不小于其左右孩子節點的關鍵字。

? 堆分為大頂堆和小頂堆,滿足Key[i]>=Key[2i+1]&&key>=key[2i+2]稱為大頂堆,滿足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]稱為小頂堆。由上述性質可知大頂堆的堆頂的關鍵字肯定是所有關鍵字中最大的,小頂堆的堆頂的關鍵字是所有關鍵字中最小的。

2.堆排序的思想

?? 利用大頂堆(小頂堆)堆頂記錄的是最大關鍵字(最小關鍵字)這一特性,使得每次從無序中選擇最大記錄(最小記錄)變得簡單。

??? 其基本思想為(大頂堆):

??? 1)將初始待排序關鍵字序列(R1,R2....Rn)構建成大頂堆,此堆為初始的無須區;

??? 2)將堆頂元素R[1]與最后一個元素R[n]交換,此時得到新的無序區(R1,R2,......Rn-1)和新的有序區(Rn),且滿足R[1,2...n-1]<=R[n];?

??? 3)由于交換后新的堆頂R[1]可能違反堆的性質,因此需要對當前無序區(R1,R2,......Rn-1)調整為新堆,然后再次將R[1]與無序區最后一個元素交換,得到新的無序區(R1,R2....Rn-2)和新的有序區(Rn-1,Rn)。不斷重復此過程直到有序區的元素個數為n-1,則整個排序過程完成。

??? 操作過程如下:

???? 1)初始化堆:將R[1..n]構造為堆;

???? 2)將當前無序區的堆頂元素R[1]同該區間的最后一個記錄交換,然后將新的無序區調整為新的堆。

??? 因此對于堆排序,最重要的兩個操作就是構造初始堆和調整堆,其實構造初始堆事實上也是調整堆的過程,只不過構造初始堆是對所有的非葉節點都進行調整。

????下面舉例說明:

???? 給定一個整形數組a[]={16,7,3,20,17,8},對其進行堆排序。

??? 首先根據該數組元素構建一個完全二叉樹,得到

?然后需要構造初始堆,則從最后一個非葉節點開始調整,調整過程如下:

20和16交換后導致16不滿足堆的性質,因此需重新調整

這樣就得到了初始堆。

即每次調整都是從父節點、左孩子節點、右孩子節點三者中選擇最大者跟父節點進行交換(交換之后可能造成被交換的孩子節點不滿足堆的性質,因此每次交換之后要重新對被交換的孩子節點進行調整)。有了初始堆之后就可以進行排序了。

此時3位于堆頂不滿堆的性質,則需調整繼續調整

這樣整個區間便已經有序了。 從上述過程可知,堆排序其實也是一種選擇排序,是一種樹形選擇排序。只不過直接選擇排序中,為了從R[1...n]中選擇最大記錄,需比較n-1次,然后從R[1...n-2]中選擇最大記錄需比較n-2次。事實上這n-2次比較中有很多已經在前面的n-1次比較中已經做過,而樹形選擇排序恰好利用樹形的特點保存了部分前面的比較結果,因此可以減少比較次數。對于n個關鍵字序列,最壞情況下每個節點需比較log2(n)次,因此其最壞情況下時間復雜度為nlogn。堆排序為不穩定排序,不適合記錄較少的排序。

轉載于:https://www.cnblogs.com/skipping/p/5426737.html

總結

以上是生活随笔為你收集整理的堆排序总结的全部內容,希望文章能夠幫你解決所遇到的問題。

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