演算法系列--堆

滑板上的老砒霜發表於2018-07-25

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);
    }
}
複製程式碼

至此堆的基礎知識就差不多了。

關注我的公眾號:

演算法系列--堆

相關文章