堆排序中--建堆的演算法複雜度分析O(n)
阿新 • • 發佈:2019-01-07
程式碼:
[cpp] view plaincopyprint?- template<class T> inlinevoid MaxHeap<T>::make_heap(vector<T> & v) {
- if (heap_.size() != 0)
- heap_.clear();
- heap_ = v;
- // start with last parent, and reheapify_down back to root
- for (int i = parent(v.size() - 1); i >= 0; i--)
- reheapify_down(i);
- v = heap_;
- }
- template<class T> inlinevoid MaxHeap<T>::reheapify_down(int i) {
- if (heap_.empty())
- return;
- int current = i, max = i;
- int left = 1, right = 2;
- int size = heap_.size();
- do {
- current = max;
- left = left_child(current);
- right = right_child(current);
- if (left < size && heap_[left] > heap_[current])
- max = left;
- if (right < size && heap_[right] > heap_[max])
- max = right;
- if (max != current)
- swap(heap_[current], heap_[max]);
- } while (max != current);
- }
看似建堆(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) 。
水平有限,歡迎指正不對之處。