《演算法導論》第三版書中陣列下標是從1開始的,但是這裡從0開始。
堆分為兩種,即最大堆和最小堆,最大堆的定義為:當陣列a大小為n時(a中有n個元素),若2*i+1=a[2*i+1];若2*i+2=a[2*i+2],則這樣的資料結構稱為最大堆。說白了就是根節點(包括子樹的根節點)的值不小於左節點和右節點的值(如果有左或右節點的話)。
最小堆和最大堆剛好相反。
這裡以最大堆為例。
首先要了解的一些知識是對於根節點i,其左孩子節點為2*i+1,右孩子節點為2*i+2;第乙個非葉節點為(n-2)/2;其中n為陣列大小。
unsigned left_child(unsigned i)
unsigned right_child(unsigned i)
下面的max_heapily()函式是使得根節點為i的樹(子樹)為最大堆
void max_heapily(unsigned a, unsigned i,unsigned n)//維持根節點為i的樹為最大堆
}
void build_max_heap(unsigned a, unsigned n)//從第乙個非葉節點到根節點調整為最大堆
}
上面的build_max_heap()函式為什麼從第乙個非葉節點開始迴圈?因為根據最大堆的定義,不但整課樹為最大堆,所有的子樹也為最大堆,第乙個非葉節點就是第一顆子樹的根節點。存在疑問的地方是,那直接max_heapily(a,0,n)不就行了嗎?不行,該函式調整的是根節點和左右孩子節點:
只有上面中的是三個節點不符合最大堆時,它才會調整子樹。
首先,把有n個元素的陣列a初始化建立為最大堆,然後迴圈執行如下過程直到陣列為空為止:(1)把堆頂a[0]元素(為最大元素)和當前最大堆的最後乙個元素交換;(2)最大堆元素個數減1;(3)由於第(1)步後根節點不再滿足最大堆的定義,所以調整根節點使之滿足最大堆的定義。
void heap_sort(unsigned a,unsigned n)
}
int main(int argc, char* argv)
; heap_sort(a, 10);
for (unsigned i = 0; i < 10; ++i)
getchar();
return 0;
}
結果:
另一種建立最大堆的方法為插入法,我們可以這樣想像,將陣列中的元素按順序逐個插入乙個二叉樹中,如插入a[0]為根節點,接著插入a[1]為左孩子節點並和根節點a[0]比較,如果不符合最大堆,則a[1]和根節點a[0]交換值;同樣,插入a[2];插入a[3],和根節點a[1]比較,如果不符合最大堆,a[3]和a[1]交換值,此時,還需要繼續往「總根」方向比較,比較a[1]和a[0],根據最大堆的性質決定是否要交換值,其他節點插入同理。
插入法建立最大堆c++**:
void max_heap_insert(unsigned a, unsigned position)
}
void build_max_heap(unsigned a,unsigned n)
}
演算法導論 堆排序
堆排序演算法 heapsort max heapify過程,其執行時間為 lg n 是保持最大堆性質的關鍵 build max heap過程,以線性時間執行,可以在無序的輸入陣列基礎上構造出最大堆 heapsort過程,執行時間 n lg n 對乙個陣列原地進行排序 heapsort過程 1 建最大...
演算法導論 堆排序習題
1.怎樣利用最大 小 堆構成的優先實現先進先出佇列或者棧 開始看這道題沒有弄清以什麼優先,原來是先進先出佇列只要保證先進來優先順序高,棧保證後進來優先順序高,然後每次彈出堆頂元素即可 2.如何在logn時間裡刪除乙個元素 思路和如何在堆中增加乙個元素是一樣的,因為堆要的形狀要保證是一顆完全二叉樹,決...
演算法導論 堆排序實現
我建立了乙個heap的資料結構,而不是像stl那樣使用函式解決堆排序,當然stl的比較優雅一點,我只是提供第二個思路 ifndef heap sort h define heap sort h include include include ifdef debug include endif deb...