1. 程式人生 > >堆排序中--建堆的演算法複雜度分析O(n)

堆排序中--建堆的演算法複雜度分析O(n)

程式碼:

[cpp] view plaincopyprint?
  1. template<class T> inlinevoid MaxHeap<T>::make_heap(vector<T> & v) {  
  2. if (heap_.size() != 0)  
  3.         heap_.clear();  
  4.     heap_ = v;  
  5. // start with last parent, and reheapify_down back to root
  6. for (int i = parent(v.size() - 1); i >= 0; i--)  
  7.         reheapify_down(i);  
  8.     v = heap_;  
  9. }  
[cpp] view plaincopyprint?
  1. template<class T> inlinevoid MaxHeap<T>::reheapify_down(int i) {  
  2. if (heap_.empty())  
  3. return;  
  4. int current = i, max = i;  
  5. int left = 1, right = 2;  
  6. int size = heap_.size();  
  7. do {  
  8.         current = max;  
  9.         left = left_child(current);  
  10.         right = right_child(current);  
  11. if (left < size && heap_[left] > heap_[current])  
  12.             max = left;  
  13. if (right < size && heap_[right] > heap_[max])  
  14.             max = right;  
  15. if (max != current)  
  16.             swap(heap_[current], heap_[max]);  
  17.     } while (max != current);  
  18. }  

看似建堆(make_heap)的複雜度為O(nlogn),實則為O(n),reheapify_down不會touch到每個節點,所以不算簡單的遞迴,只能算疊加。證明如下:

因為堆構建的是一顆平衡二叉樹。於是有:

1. 一棵擁有n個節點的平衡二叉樹,樹高 h 約為 lg n 。

2. 樹的第 i 層 最多有節點 2^i 個。注意,第 i 層的高度為 i + 1。如第0層的高度為1,擁有1個根節點。

那麼做reheapify_down時,最底層(h-1)的節點不會動,倒數第二層(h-2)的節點最多往下移動一次,倒數第三層(h-3)的節點最多往下移動2次....第0層的節點往下最多移動(h-1)次。

所以,最壞情況下,每層所有節點都會往下移到最底層。

則,所有操作總和為     S = 2^(h-1)*0 + 2^(h-2)*1 + 2^(h-3) * 2 + ... + 2^1*(h-2) + 2^0*(h-1)        ----- (1)

把(1)式乘以2,再減去(1)式, 可得

S = 2^(h-1) + 2^(h-2) + ... + 2^1 - 2^0*(h-1)  = 2(1-2^(h-1))/(1-2) - (h-1) = 2^h - h- 1      ---- (2)

把h = lg n 代入 (2)式, 得 S = n - lgn - 1 <= n   (n >=1)

故而, 建堆複雜度為O(n) 。

水平有限,歡迎指正不對之處。