0.引言
堆是一種比較常見的資料結構,堆排序也是面試時會經常遇到的問題,今天就分析一下堆。
1.堆結構
堆是一種類似於樹的資料結構,父節點和子節點之間存在一定的關係,子節點的數量根據堆的型別來決定,最長見得就是每個父節點最多兩個子節點的二叉堆。
如圖所示,我們用一個陣列類模擬二叉樹以構建二叉堆,從圖可以看出,堆是從陣列的1開始而不是0開始,這主要就是為了構建子節點和父節點的關係,我們可以很清楚的看到這種關係:leftNodeIndex=rootIndex2; rightNodeIndex=rootIndex2+1。 我們還可以發現這個堆的父節點都是大於其子節點的,這就是一個最大堆,可以用來進行從小到大的堆排序。
2.構建最大堆
構建最大堆,首先明確一個規則,堆的葉子節點的位置,假設堆的數量為N=7; 那麼它的葉子節點就是 N/2+1,N/2+2,N/2+3,N/2+4,如圖所示:
那麼現在假設給了一個堆陣列,構建成一個最大堆,從葉子節點的上一層節點開始直到根節點進行最大堆化操作void build_maxheap (int Arr[ ])
{
for(int i = N/2 ; i >= 1 ; i-- )
{
max_heapify (Arr, i) ;
}
}
void max_heapify (int Arr[ ], int i, int N)
{
int left = 2*i //left child
int right = 2*i +1 //right child
if(left<= N and Arr[left] > Arr[i] )
largest = left;
else
largest = i;
if(right <= N and Arr[right] > Arr[largest] )
largest = right;
if(largest != i )
{
swap (Arr[i] , Arr[largest]);
max_heapify (Arr, largest,N);
}
}
複製程式碼
max_heapify就是遞迴的將父節點和左右子節點進行大小比較,將較大的值放到父節點的位置。下圖演示了一個構建最大堆的過程
最小堆和最大堆相反,就是根節點是小於子節點的,只要將max_heapify稍加改造就可以了,就不再贅言了。3.堆排序
說到應用了,如果給定了一個無序的陣列按照從小到大排序,那麼我們就可以利用最大堆的性質在O(NlogN)的時間複雜度內進行排序。 堆排序一般按照如下步驟: 1.構建最大堆。 2.交換第一個元素和最後一個元素的位置。 3.從根節點開始,進行堆最大化操作(max_heapfy),注意此時待排序節點的個數為N-1,因為第二步的時候已經排序好一個值了。 4.重複2,3步驟直到排序完成。 如果是從大到小排序,那麼就用最小堆。 排序過程入下圖:
void heap_sort(int Arr[ ])
{
int heap_size = N;
build_maxheap(Arr);
for(int i = N; i>=2 ; i-- )
{
swap(Arr[ 1 ], Arr[ i ]);
heap_size = heap_size-1;
max_heapify(Arr, 1, heap_size);
}
}
複製程式碼
至此堆的基礎知識就差不多了。
關注我的公眾號: