演算法導論 第6章 堆排序

來源:互聯網
上載者:User
一、概念1.定義(1)堆heap堆是一種數組對象The  (binary) heap  data structure is an array object that can be viewed as a nearly complete binary tree(2)最大堆max-heap

for every node  i  other than the root,A[PARENT( i)]  ≥ A[i]

(3)最小堆min-heap

for every node  i  other than the root,A[PARENT( i)]  ≤ A[i]

(4) height

Viewing a heap as a tree, we define the  height  of a node in a heap to be the number of edges on the longest simple downward path from the node to a leaf, and we define the height of the heap to be the height of its root

2.性質

(1)堆可以被視頻一棵完全二叉樹,二叉樹的層次遍曆結果與數組元素的順序對應,樹根為A[1]。對於數組中第i個元素,具體計算如下

PARENT(i)    return i/2LEFT(i)    return 2iRIGHT(i)    return 2i+1

 

二、程式1.堆的結構

A[N]:堆數組

length[A]:數組中元素的個數

heap-size[A]:存放在A中的堆的元素個數

2.在堆上的操作(1)MAX-HEAPIFY(A, i)(2)BUILD-MAX-HEAP(A)(3)HEAPSORT(A)3.堆的應用優先順序隊列(1)HEAP-MAXIMUM(A)(2)HEAP-INCREASE-KEY(A, i, key)(3)HEAP-EXTRACT-KEY(A)(4)MAX-HEAP-INSERT(A, key)

 

//標頭檔#include <iostream>#include <stdio.h>using namespace std;//宏定義#define N 1000#define PARENT(i) (i)>>1#define LEFT(i) (i)<<1#define RIGHT(i) ((i)<<1)+1class Heap{public://成員變數int A[N+1];int length;int heap_size;//構造與析構Heap(){}Heap(int size):length(size),heap_size(size){}~Heap(){}//功能函數void Max_Heapify(int i);void Build_Max_Heap();void HeapSort();//優先隊列函數void Heap_Increase_Key(int i, int key);void Max_Heap_Insert(int key);int Heap_Maximum();int Heap_Extract_Max();void Heap_Delete(int i);//輔助函數void Print();};//使以i結點為根結點的子樹成為堆,調用條件是確定i的左右子樹已經是堆,時間是O(lgn)//遞迴方法void Heap::Max_Heapify(int i){Print();int l = LEFT(i), r = RIGHT(i), largest;//選擇i、i的左、i的右三個結點中值最大的結點if(l <= heap_size && A[l] > A[i])largest = l;else largest = i;if(r <= heap_size && A[r] > A[largest])largest = r;//如果根最大,已經滿足堆的條件,函數停止//否則if(largest != i){//根與值最大的結點互動swap(A[i], A[largest]);//交換可能破壞子樹的堆,重新調整子樹Max_Heapify(largest);}}//建堆,時間是O(nlgn)void Heap::Build_Max_Heap(){heap_size = length;//從堆中最後一個元素開始,依次調整每個結點,使符合堆的性質for(int i = length / 2; i >= 1; i--)Max_Heapify(i);}//堆排序,時間是O(nlgn)void Heap::HeapSort(){//建立一個最大堆Build_Max_Heap();//每次將前i個元素構成最大堆for(int i = length; i > 1; i--){//將前i個元素中的最大值存入到A[i]中swap(A[1], A[i]);//堆的大小減一heap_size--;//只有堆頂的性質可能會被破壞Max_Heapify(1);}}//將元素i的關鍵字增加到key,要求key>=A[i]void Heap::Heap_Increase_Key(int i, int key){if(key < A[i]){cout<<"new key is smaller than current key"<<endl;exit(0);}A[i] = key;//跟父比較,若A[PARENT(i)]<A[i],則交換//若運行到某個結點時A[PARENT(i)]>A[i],就跳出迴圈while(A[PARENT(i)] > 0 && A[PARENT(i)] < A[i]){swap(A[PARENT(i)], A[i]);i = PARENT(i);}}//把key插入到集合A中void Heap::Max_Heap_Insert(int key){if(heap_size == N){cout<<"heap is full"<<endl;exit(0);}heap_size++;length++;A[heap_size] = -0x7fffffff;Heap_Increase_Key(heap_size, key);}//返回A中最大關鍵字,時間O(1)int Heap::Heap_Maximum(){return A[1];}//去掉並返回A中最大關鍵字,時間O(lgn)int Heap::Heap_Extract_Max(){if(heap_size < 1){cout<<"heap underflow"<<endl;exit(0);}//取出最大值int max = A[1];//將最後一個元素補到最大值的位置A[1] = A[heap_size];heap_size--;//重新調整根結點Max_Heapify(1);//返回最大值return max;}//刪除堆中第i個元素void Heap::Heap_Delete(int i){if(i > heap_size){cout<<"there's no node i"<<endl;exit(0);}//把最後一個元素補到第i個元素的位置int key = A[heap_size];heap_size--;//如果新值比原A[i]大,則向上調整if(key > A[i])Heap_Increase_Key(i, key);else//否則,向下調整{A[i] = key;Max_Heapify(i);}}void Heap::Print(){int i;for(i = 1; i <= length; i++){if(i > 1)cout<<',';else cout<<"==> A = {";cout<<A[i];}cout<<'}'<<endl;}
三、練習6.1 堆
6.1-1最多2^(h+1) - 1, 最少2 ^ h(當樹中只有一個結點時,高度是0)6.1-2根據上一題,2^h <= n <= 2^(h+1) - 1 ==> h <= lgn <= h + 1 ==> lgn = h6.1-3根據定義(1)max-heap的定義==>A[PARENT(i)]>=A[i]==>A[1]>A[2],A[3]==>A[1]>A[4],A[5],A[6],A[7]==>……==>the root of the subt ree contains the largest value6.1-4葉子上6.1-5是最小堆或最大堆6.1-6不是,7是6的左孩子,但7>66.1-7根據性質(1)A[2i]、A[2i+1]是A[i]的孩子==>若2i<=n&&2i+1<=n,則A[i]有孩子==>若2i>n,則A[i]是葉子==>the leaves are the nodes indexed by ?n/2 ? + 1, ?n/2 ? + 2, . . . , n

 

6.2 保持堆的性質
6.2-1    A = {27,17,3,16,13,10,1,5,7,12,4,8,9,0}==> A = {27,17,10,16,13,3,1,5,7,12,4,8,9,0}==> A = {27,17,10,16,13,9,1,5,7,12,4,8,3,0}6.2-2MIN-HEAPIFY(A, i) 1    l <- LEFT(i) 2    r <- RIGHT(i) 3    if l <= heap-size[A] and A[l] < A[i] 4        then smallest <- l 5        else smallest <- i 6    if r <= heap-size[A] and A[r] < [smallest] 7        then smallest <- r 8    if smallest != i 9        then exchange A[i] <-> A[smallest]10                MIN_HEAPIFY(A, smallest)6.2-3沒有效果,程式終止6.2-4i > heap-size[A]/2時,是葉子結點,也沒有效果,程式終止6.2-5 我還是比較喜歡用C++,不喜歡用虛擬碼void Heap::Max_Heapify(int i){int l = (LEFT(i)), r = (RIGHT(i)), largest;//選擇i、i的左、i的右三個結點中值最大的結點if(l <= heap_size && A[l] > A[i])largest = l;else largest = i;if(r <= heap_size && A[r] > A[largest])largest = r;//如果根最大,已經滿足堆的條件,函數停止//否則while(largest != i){//根與值最大的結點互動swap(A[i], A[largest]);//交換可能破壞子樹的堆,重新調整子樹i = largest;l = (LEFT(i)), r = (RIGHT(i));//選擇i、i的左、i的右三個結點中值最大的結點if(l <= heap_size && A[l] > A[i])largest = l;else largest = i;if(r <= heap_size && A[r] > A[largest])largest = r;}}6.2-6MAX-HEAPIFY中每迴圈一次,當前處理的結點的高度就會+1,最壞情況下,結點是根結點的時候停止,此時結點高度是logn,因此最壞已耗用時間是logn

 

6.3 建堆6.3-1
    A = {5,3,17,10,84,19,6,22,9}==> A = {5,3,17,22,84,19,6,10,9}==> A = {5,3,19,22,84,17,6,10,9}==> A = {5,84,19,22,3,17,6,10,9}==> A = {84,5,19,22,3,17,6,10,9}==> A = {84,22,19,5,3,17,6,10,9}==> A = {84,22,19,10,3,17,6,5,9}

6.3-2

因為MAX-HEAPIFY中使用條件是當前結點的左孩子和右孩子都是堆假設對i執行MAX-HEAPIFY操作,當i=j時迴圈停止,結果是從i到j的這條路徑上的點滿足最大堆的性質,但是PARENT[i]不一定滿足。甚至有可能在滿足A[PARENT(i)]>A[i]的情況下因為執行了MAX-HEAPIFY(i)而導致A[PARENT(i)]<A[i],例如,因此一定要先執行MAX-HEAPIFY(i)才能執行MAX-HEAPIFY(PARENT(i))

6.3-3見http://blog.csdn.net/lqh604/article/details/73818936.4 堆排序的演算法

6.4-1    A = {5,13,2,25,7,17,20,8,4}==> A = {25,13,20,8,7,17,2,5,4}==> A = {4,13,20,8,7,17,2,5,25}==> A = {20,13,17,8,7,4,2,5,25}==> A = {5,13,17,8,7,4,2,20,25}==> A = {17,13,5,8,7,4,2,20,25}==> A = {2,13,5,8,7,4,17,20,25}==> A = {13,8,5,2,7,4,17,20,25}==> A = {4,8,5,2,7,13,17,20,25}==> A = {8,7,5,2,4,13,17,20,25}==> A = {4,7,5,2,8,13,17,20,25}==> A = {7,4,5,2,8,13,17,20,25}==> A = {2,4,5,7,8,13,17,20,25}==> A = {5,4,2,7,8,13,17,20,25}==> A = {2,4,5,7,8,13,17,20,25}==> A = {4,2,5,7,8,13,17,20,25}==> A = {2,4,5,7,8,13,17,20,25}==> A = {2,4,5,7,8,13,17,20,25}6.4-2不知道題目是什麼意思,是證明題?6.4-3按遞增排序的數組,已耗用時間是nlgn按遞減排序的數組,已耗用時間是n6.4-4堆排序演算法中,對堆中每個結點的處理過程為:(1)取下頭結點,O(1)(2)把最後一個結點移到根結點位置,O(1)(3)對該結點執行MAX-HEAPIFY,最壞時間為O(lgn)對每個結點處理的最壞時間是O(lgn),每個結點最多處理一次。因此最壞已耗用時間是O(nlgn)

6.4-5求高人解答,點擊開啟連結6.5 優先順序隊列

6.5-1    A = {15,13,9,5,12,8,7,4,0,6,2,1}==> A = {1,13,9,5,12,8,7,4,0,6,2,1}==> A = {13,1,9,5,12,8,7,4,0,6,2,1}==> A = {13,12,9,5,1,8,7,4,0,6,2,1}==> A = {13,12,9,5,6,8,7,4,0,1,2,1}return 156.5-2    A = {15,13,9,5,12,8,7,4,0,6,2,1}==> A = {15,13,9,5,12,8,7,4,0,6,2,1,-2147483647}==> A = {15,13,9,5,12,8,7,4,0,6,2,1,10}==> A = {15,13,9,5,12,10,7,4,0,6,2,1,8}==> A = {15,13,10,5,12,9,7,4,0,6,2,1,8}6.5-3HEAP-MINIMUM(A)1    return A[1]HEAP-EXTRACR-MIN(A)1    if heap-size[A] < 12        then error "heap underflow"3    min <- A[1]4    A[1] <- A[heap-size[A]]5    heap-size[A] <- heap-size[A] - 16    MIN-HEAPIFY(A, 1)7    return minHEAP-DECREASE-KEY(A, i, key)1    if key > A[i]2        then error "new key is smaller than current key"3    A[i] <- key4    while i > 1 and A[PARENT(i)] > A[i]5        do exchange A[i] <-> A[PARENT(i)]6              i <- PARENT(i)MIN-HEAP-INSERT1    heap-size[A] <- heap-size[A] + 12    A[heap-size[A]] <- 0x7fffffff3    HEAP-INCREASE-KEY(A, heap-size[A], key)6.5-4要想插入成功,key必須大於這個初值。key可能是任意數,因此初值必須是無限小6.5-6FIFO:以進入隊列的時間作為權值建立最小堆棧:以進入棧的時間作為權值建立最大堆6.5-7void Heap::Heap_Delete(int i){if(i > heap_size){cout<<"there's no node i"<<endl;exit(0);}int key = A[heap_size];heap_size--;if(key > A[i])   //最後一個結點不一定比中間的結點最Heap_Increase_Key(i, key);else{A[i] = key;Max_Heapify(i);}}

6.5-8見演算法導論6.5-8堆排序-K路合并四、思考題
6-1 用插入方法建堆

void Heap::Build_Max_Heap(){heap_size = 1;//從堆中最後一個元素開始,依次調整每個結點,使符合堆的性質for(int i = 2; i <= length; i++)Max_Heap_Insert(A[i]);}答:a)A = {1,2,3};b)MAX-HEAP-INSERT的過程如下:加入大小為-0x7FFFFFFF的新結點,O(1)將該值調整為key,最壞情況下為O(lgn)對每個結點都要執行一次插入操作,因此最壞時間為O(nlgn)
6-2 對d叉堆的分析
a)根結點是A[1],根結點的孩子是A[2],A[3],……,A[d+1]PARENT(i) = (i - 2 ) / d + 1  CHILD(i, j ) = d * (i - 1) + j + 1  b)lgn/lgd  c)HEAP-EXTRACR-MAX(A)與二元堆積的實現相同,其調用的MAX-HEAPIFY(A, i)要做部分更改,時間複雜度是O(lgn/lgd * d)  MAX-HEAPIFY(A, i)1    largest <- A[i]  2    for j <- 1 to d3        k <- CHILD(i, j)  4        if k <= heap-size[A] and A[j] > A[largest]  5            largest <- k6    if largest != i  7    then exchange A[i] <-> A[largest]  8             MAX-HEAPIFY(A, largest)  d)和二元堆積的實現完全一樣,時間複雜度是O(lgn/lgd)  e)和二元堆積的實現完全一樣,時間複雜度是O(lgn/lgd) 
6-3 Young氏矩陣見演算法導論
6-3 Young氏矩陣

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.