日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

堆排序

 renhl252 2014-09-29

【1】完全二叉樹

在學習堆排序之前,我們先要了解一下完全二叉樹。

若設二叉樹的深度為h,除第h層外,其它各層 (1...h-1) 的結點數(shù)都達到最大個數(shù),第h層所有的結點都連續(xù)集中在最左邊,這就是完全二叉樹。 

完全二叉樹特點: 

(1) 滿二叉樹是完全二叉樹,完全二叉樹不一定是滿二叉樹。 

(2) 在滿二叉樹的最下一層上,從最右邊開始連續(xù)刪去若干結點后得到的二叉樹仍然是一棵完全二叉樹。 

(3) 在完全二叉樹中,若某個結點沒有左孩子,則它一定沒有右孩子,即該結點必是葉結點。

(4)如下圖所示,結點C沒有左孩子而有右孩子F,故它不是一棵完全二叉樹。

(5)如下圖所示,兩棵完全二叉樹(右邊b為滿二叉樹)。

(6)下圖是一棵天然的完全二叉樹

【2】堆(Heap)

在程序設計領域,堆(Heap)的概念主要有以下兩種:

(1)一種數(shù)據(jù)結構,邏輯上是一顆完全二叉樹,存儲上是一個數(shù)組對象(二叉堆)。也正是本文談及的堆。

(2)存儲區(qū),是軟件系統(tǒng)可以編程的內(nèi)存區(qū)域(即就是動態(tài)申請的區(qū)域)。

數(shù)據(jù)結構中的堆實質(zhì)上是滿足一定性質(zhì)的完全二叉樹:二叉樹中任一非葉子結點關鍵字的值均小于(大于)它的孩子結點的關鍵字。

在小根堆中,第一個元素(完全二叉樹的根結點)的關鍵字最?。?/span>

大根堆中,第一個元素(完全二叉樹的根結點)的關鍵字最大,

顯然,堆中任一子樹仍是一個堆。

假設,節(jié)點I是數(shù)組A中下標為i的節(jié)點:

那么,節(jié)點I的父節(jié)點下標為:(i-1)/2

節(jié)點I的左子節(jié)點下標為:2 * i + 1

節(jié)點I的右子節(jié)點下標為:2 * i + 2

詳細圖解如下存儲與邏輯表示

【3】堆存儲與邏輯結構表示

如下圖所示:

注意:示例中的邏輯結構堆不是最大堆也不是最小堆,僅僅只是為了便于理解堆的邏輯結構。

【4】堆排序定義

n個關鍵字序列Kl,K2,…,Kn稱為堆,當且僅當該序列滿足如下性質(zhì)(簡稱為堆性質(zhì)):

(1) ki ≤ K2i 且 ki ≤ K2i+1  或  (2) Ki ≥ K2i 且 ki ≥ K2i+1((i=1,2,…,[n/2],其中[]表示上取整)

若將此序列所存儲的向量R[1..n]看做是一棵完全二叉樹的存儲結構,則堆實質(zhì)上是滿足如下性質(zhì)的完全二叉樹:

樹中任一非葉結點的關鍵字均不大于(或不小于)其左右孩子(若存在)結點的關鍵字。

【5】堆排序思想

堆排序利用了大根堆(或小根堆)堆頂(根節(jié)點)記錄的關鍵字最大(或最小)這一特征,使得在當前無序區(qū)中選取最大(或最小)關鍵字的記錄變得簡單。

(1)用大根堆排序的基本思想

<1>先將初始文件R[1.....N]建成一個大根堆,此堆為初始的無序區(qū)。

<2>再將關鍵字最大的記錄R[1](即堆頂)和無序區(qū)的最后一個記錄R[n]交換

由此得到新的無序區(qū)R[1..n-1]和有序區(qū)R[n],且滿足R[1..n-1].keys ≤ R[n].key

<3>由于交換后新的根R[1]可能違反堆性質(zhì),故應將當前無序區(qū)R[1..n-1]調(diào)整為堆。

然后再次將R[1..n-1]中關鍵字最大的記錄R[1]和該區(qū)間的最后一個記錄R[n-1]交換

由此得到新的無序區(qū)R[1..n-2]和有序區(qū)R[n-1..n],且仍滿足關系R[1..n-2].keys  ≤  R[n-1..n].keys,同樣要將R[1..n-2]調(diào)整為堆。

直到無序區(qū)只有一個元素為止。

(2)大根堆排序算法的基本操作:

<1> 初始化操作:將R[1..n]構造為初始堆;

<2>每一趟排序的基本操作:將當前無序區(qū)的堆頂記錄R[1]和該區(qū)間的最后一個記錄交換,然后將新的無序區(qū)調(diào)整為堆(亦稱重建堆)。

注意:

<1>只需做n-1趟排序,選出較大的n-1個關鍵字即可以使得文件遞增有序。

<2>用小根堆排序與利用大根堆類似,只不過其排序結果是遞減有序的。

堆排序和直接選擇排序相反:在任何時刻,堆排序中無序區(qū)總是在有序區(qū)之前,且有序區(qū)是在原向量的尾部由后往前逐步擴大至整個向量為止。

(3)排序邏輯結構演示如下圖所示:

請結合以上邏輯分析內(nèi)容或以下實現(xiàn)代碼加深對堆排序的理解。

【6】堆排序?qū)崿F(xiàn)

(1)C++實現(xiàn)與測試代碼如下:

復制代碼
  1 #include<iostream>
  2 using namespace std;
  3 
  4 void swap(int &a,int &b)
  5 {
  6     int temp = a;
  7     a = b;
  8     b = temp;
  9 }
 10 
 11 void  PrintArr(int ar[],int n)
 12 {
 13     for(int i = 0; i < n; ++i)
 14         cout<<ar[i]<<" ";
 15     cout<<endl;
 16 }
 17 
 18 void AdjustHeap(int data[], int start, int m)  
 19 {  
 20     int i = 0, j = 0;  
 21     int value = data[start];  
 22     for(i = start, j = 2*i + 1; j <= m; i = j, j = 2*j+1)  
 23     {  
 24         cout<<"i = "<<i<<" j = "<<j<<" value = "<<value<<endl;
 25         if(j < m  && data[j] < data[j+1])  
 26         {
 27             ++j;
 28         }
 29         if(value > data[j])    
 30             break;  
 31         else   
 32             data[i] = data[j];     
 33         PrintArr(data, 6);
 34     }  
 35     data[i] = value; 
 36     PrintArr(data, 6);
 37 }  
 38 
 39 void HeapSort(int data[],int size)
 40 {
 41     int i = 0;
 42     cout<<"調(diào)整為最大堆的過程:"<<endl;
 43     for(i = size/2-1; i >= 0; --i)
 44     {
 45         cout<<"i = "<<i<<" size = "<<size<<endl;
 46         AdjustHeap(data, i, size-1);
 47     }
 48     cout<<"調(diào)整為最大堆結果如下:"<<endl;
 49     PrintArr(data, size);
 50     cout<<"整個排序過程如下:"<<endl;
 51     for(i = size - 1; i >= 1; --i)
 52     {
 53         swap(data[0], data[i]);
 54         PrintArr(data, size);
 55         AdjustHeap(data, 0, i-1);        
 56         PrintArr(data, size);
 57     }
 58 } 
 59 
 60 void  main()
 61 {
 62     int  ar[] = {12, 88, 32, 5, 16, 67};
 63     int len = sizeof(ar)/sizeof(int);
 64     cout<<"原數(shù)據(jù)序列為:"<<endl;
 65     PrintArr(ar, len);
 66     HeapSort(ar, len);
 67     cout<<"排序后結果如下:"<<endl;
 68     PrintArr(ar, len);
 69 } 
 70 /*
 71 原數(shù)據(jù)序列為:
 72 12 88 32 5 16 67
 73 調(diào)整為最大堆的過程:
 74 i = 2 size = 6
 75 i = 2 j = 5 value = 32
 76 12 88 67 5 16 67
 77 12 88 67 5 16 32
 78 i = 1 size = 6
 79 i = 1 j = 3 value = 88
 80 12 88 67 5 16 32
 81 i = 0 size = 6
 82 i = 0 j = 1 value = 12
 83 88 88 67 5 16 32
 84 i = 1 j = 3 value = 12
 85 88 16 67 5 16 32
 86 88 16 67 5 12 32
 87 調(diào)整為最大堆結果如下:
 88 88 16 67 5 12 32
 89 整個排序過程如下:
 90 32 16 67 5 12 88
 91 i = 0 j = 1 value = 32
 92 67 16 67 5 12 88
 93 67 16 32 5 12 88
 94 67 16 32 5 12 88
 95 12 16 32 5 67 88
 96 i = 0 j = 1 value = 12
 97 32 16 32 5 67 88
 98 32 16 12 5 67 88
 99 32 16 12 5 67 88
100 5 16 12 32 67 88
101 i = 0 j = 1 value = 5
102 16 16 12 32 67 88
103 16 5 12 32 67 88
104 16 5 12 32 67 88
105 12 5 16 32 67 88
106 i = 0 j = 1 value = 12
107 12 5 16 32 67 88
108 12 5 16 32 67 88
109 5 12 16 32 67 88
110 5 12 16 32 67 88
111 5 12 16 32 67 88
112 排序后結果如下:
113 5 12 16 32 67 88
114  */
復制代碼

(2)堆排序代碼示例:

復制代碼
 1 void swap(int &a,int &b)
 2 {
 3     int temp = a;
 4     a = b;
 5     b = temp;
 6 }
 7 
 8 void AdjustHeap(int data[], int start, int m)  
 9 {  
10     int i = 0, j = 0;  
11     int value = data[start];  
12     for(i = start, j = 2*i + 1; j <= m; i = j, j = 2*j+1)  
13     {  
14         if(j < m  && data[j] < data[j+1])  
15         {
16             ++j;
17         }
18         if(value > data[j])    
19             break;  
20         else   
21             data[i] = data[j];     
22     }  
23     data[i] = value; 
24 
25 }  
26 
27 void HeapSort(int data[],int size)
28 {
29     int i = 0;
30     for(i = size/2-1; i >= 0; --i)
31     {
32         AdjustHeap(data, i, size-1);
33     }
34     for(i = size - 1; i >= 1; --i)
35     {
36         swap(data[0], data[i]);
37         AdjustHeap(data, 0, i-1);        
38     }
39 } 
復制代碼

堆排序的實現(xiàn)代碼有很多種實現(xiàn)方式,在此僅作為參考。

【7】堆排序分析

堆排序的時間,主要由建立初始堆和反復重建堆這兩部分的時間開銷構成,它們均是通過調(diào)用堆調(diào)整函數(shù)實現(xiàn)的。

堆排序的最壞時間復雜度為O(nlgn)(參見隨筆《算法復雜度》)。堆排序的平均性能較接近于最壞性能。

由于建初始堆所需的比較次數(shù)較多,所以堆排序不適宜于記錄數(shù)較少的文件。

堆排序是就地排序,輔助空間為O(1)。

它是不穩(wěn)定的排序方法(參見隨筆《常用排序算法穩(wěn)定性分析》)。

 

Good Good Study, Day Day Up.

順序  選擇  循環(huán)  堅持  總結

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多