各位讀者,大家好。 因為算法和數據結構相關的知識都是在國外學的,所以有些詞匯翻譯的可能不准確,然后一些源代碼的注釋可能是英文的,如有給大家帶來什么不方便,請見諒。今天我想寫一下Heap相關的知識,從基本的結構到最后的一些常用functions. Heap 的數據結構其實可以看成Array, 例如a[] = {5,3,6,8,2,1,0}這個數組, 我們可以將其看作如下的結構:
Heap又可以分成2種類型:Max-Heap 和 Min-Heap。 Max-Heap的意思是每一個node的key值都要大於它的children的key值;反之Min-Heap的的結構是每個node的key值都小於它的children的key值。 例如一個Max-Heap的結構如下:
對於以上的Heap 數據結構的分析,可以分析出對於一個含有N個元素的heap或者稱之為array,其heap的結構的的高度(level)是1+logN. 例如上面的結構就是1+log7 = 3 層。
如果一個heap當中只有一個element破壞了Max-heap/Min-Heap structure的結構,那么如果希望重構這個heap讓其重新維持Max/Min的話,這個element需要跟它的children中的較大的值交換,一直交換到它的children都小於它的key值為止,這個過程最多進行這個tree的高度次(即:the height of tree), 而這個height就是O(logN)。我們稱這個過程為Max-Heapify或者Min-Heapify。以下展示的是C++的代碼來實現Max-heapify的過程, 如下:
/* heapify() function is used to keep the heap structure as max/min heap. If there is a node voilate the max/min heap, this function will try to correct it and restructure it still keep the max/min heap property. parameter: 1. a[], the array 2. i; where the node violate the max/min heap 3. n; the numbers of the a[]; return: void */ void heapify(int a[], int i, int n){ int j, temp; j = 2*i;//the node i's left node if (j >= n){//i is the leaf of the tree return; } temp = a[i]; while (j < n) {//i is not the leaf if (a[j]<a[j+1]) {//left child is less than right child j = j + 1; } if (temp>a[j]) { break; } if (temp <= a[j]) {// if node i violate the structure, exchange the values. a[j/2] = a[j]; a[j] = temp; j = j * 2; } } }
以上的代碼展示的是max-heapify 的過程, 那么如何將一個亂續的heap或者array重構成一個max-heap或者min-heap呢?其實有了以上的功能,將一個完全雜亂的heap裝換成max-heap就很簡單了。我們只需要從倒數第二層的最左邊的一個element開始一直向上面的level的nodes做Max-heapify的過程utill to the root of the tree, 最后就一定能將整個heap轉化成Max-Heap. 倒數第二層的最左邊的一個element的index是N/2 - 1; 這中間的整個過程如下所示:
將整個unsorted heap轉化成Max-Heap的過程的時間復雜度Efficiency = O(N), 而不是O(LogN); 這個復雜度的推導過程下次再跟大家解釋,是通過數學運算推導出來的,這里就不詳細解釋了。其實這個代碼很簡單,他的C++的實現代碼如下:
/* buildMaxHeap functions is used to force and restructure the heap to an maximum heap structure parameters: 1: a[]; 2: n;// the number of the arrary return void */ void buildMaxHeap(int a[], int n){ for (int i = n/2-1; i >= 1; i --) { heapify(a, i, n); } }
進過以上的過程,我們知道了如何將一個無序的heap或者array轉換成Max-Heap, 那么接下來我們就解釋一下如何將獲得的Max-heap進行排序,它主要經過一下幾個過程:
1. 交換heap的最后一個key a[N]和heap的root的key a[1]; 此時a[1]破壞了Max-heap的structure,a[N]是最大值。
2. 我們對除了最后幾個已經交換過值的elements剩下的tree進行heapfy的過程;//假如從[j.....N]的elements是之前比較過的,那么就只對[1......j-1]進行heapify的過程。
其具體的c++代碼的實現過程如下所示:
/* heapSort function is to sort the heap in an descending or ascending order parameter: 1, a[], //the array 2, n,// how many nodes should be checked in the heapify function, actuall here is not all the node should be checked return void */ void heapSort(int a[], int n){ int temp; for (int i = n-1; i >= 2; i --) {//the last indices of array is n-1, loop until to the root temp = a[1]; a[1] = a[i]; a[i] = temp; heapify(a, 1, i-1); } }
綜合以上的不做,我們已經可以完成對一個完全無序的array或者heap進行heap-sort的過程,它的時間復雜度如下:
Efficiency = O(N)+O(1)+O(N*logN) = O(N*logN);
那么heap的總結就結束了,下周准備寫一些Binary Search Tree (BST)的知識。
如果有什么錯誤的地方,歡迎大家留言指正,謝謝。