堆和堆的構建
什麼是堆
堆是一種特殊的二叉樹,具備以下特性:
如果每個節點的值都大於等於左右孩子節點的值,這樣的堆叫大頂堆;如果每個節點的值都小於等於左右孩子節點的值,這樣的堆叫小頂堆。
上圖中,左側的堆是大頂堆,右側的堆是小頂堆,我們還可以得出這個結論:對應大頂堆,堆頂一定是最大值;對於小頂堆,堆頂一定是最小值。
如何構建堆
我們在介紹二叉樹的定義和儲存的時候說到,由於完全二叉樹的特殊性,可以通過陣列來儲存,堆也是完全二叉樹,所以我們完全可以通過陣列來儲存。在使用陣列儲存堆的時候,把第乙個索引位置留空,從第二個索引位置開始儲存堆元素,這樣,對於索引值為i
的元素而言,其子節點索引分別為2i
和2i+1
。
下面我們就來看如何在堆中插入新節點,以大頂堆為例,從葉子結點插入,如果比父級元素大,則與父級元素交換位置,依次類推,直到到達根節點(小頂堆恰好相反):
注:構建堆的過程叫堆化實現**下面是對應的 php 實現**:
<?php
class heap
public function insert($data)
$this->count++;
$this->a[$this->count] = $data;
$i = $this->count;
while (floor($i/2) > 0 && $this->a[floor($i/2)] < $this->a[$i])
return true;
}public function __tostring()
}
我們可以為這段**編寫一段測試**:
$heap = new heap();
$data = range(1, 10);
shuffle($data);
foreach ($data as $num)
}print_r($heap);
列印結果如下,符合堆定義,表明堆構建成功:
堆排序及其應用
堆排序
但是這裡有乙個問題,每次從堆頂刪除元素後,需要從子節點中取值補齊堆頂,依次類推,直到葉子節點,就會致使儲存堆的陣列出現「空洞」:
解決辦法是將陣列中的最後乙個元素(最右邊的葉子節點)移到堆頂,再重新對其進行堆化:
這樣,就完美解決了「陣列空洞」的問題。
實現**
下面我們將堆排序過程轉化為對應的 php 實現**如下:
<?php
class heap
public function insert($data)
$this->count++;
$this->a[$this->count] = $data;
$i = $this->count;
while (floor($i/2) > 0 && $this->a[floor($i/2)] < $this->a[$i])
return true;
}public function remove()
if ($i*2 + 1 <= $this->count && $this->a[$i*2+1] > $this->a[$maxpos])
if ($maxpos == $i)
$temp = $this->a[$i];
$this->a[$i] = $this->a[$maxpos];
$this->a[$maxpos] = $temp;
$i = $maxpos;
}return $removedata;
}public function __tostring()
}
我們可以結合堆化和刪除方法,寫一段測試**:
$heap = new heap();
$data = range(1, 10);
shuffle($data);
foreach ($data as $num)
}$sorteddata = ;
while ($removeddata = $heap->remove())
print_r($sorteddata);
列印的結果如下:
說明堆排序成功,資料變成了從大到小的排序序列。
複雜度分析
我們先看時間複雜度,對堆排序而言,分為兩個階段,乙個是堆的構建,乙個是堆頂元素的刪除。對於n
個節點的堆化而言,通過陣列儲存,對應的時間複雜度是o(n)
,對於堆頂元素的刪除而言,需要遍歷n
個節點,並且,每次刪除後需要重新堆化,對應的平均時間複雜度是o(nlogn)
。所以綜合下來,堆排序的時間複雜度和快速排序、歸併排序一樣,是o(nlogn)
。
堆排序的過程中,涉及到不相鄰元素的交換(刪除堆頂元素的時候),所以不是穩定的排序演算法。
我們在刪除堆頂元素的時候,使用了額外的儲存空間存放被刪除的堆頂元素,但是,我們也可以對這個過程進行優化,從而做到原地排序,感興趣的同學可以試試。
堆排序的應用
排序 4 堆排序
將待排序的序列構成乙個大頂堆。此時,序列的最大值就是堆頂的根結點。將它移走 就是,將其與堆陣列的末尾元素交換,此時末尾的元素就是最大值 然後將剩餘的n 1個序列重新構成乙個堆,如此反覆。其中關鍵問題 1 如何將無序序列構成乙個堆 2 輸出堆頂元素後,如何調整公升序元素為乙個堆 4.堆排序 堆調整 v...
排序二 堆排序
子結點的鍵值或索引總是小於 或者大於 它的父節點。堆通過一維陣列實現。在起始陣列為 0 的情形中 父節點i的左子節點在位置 2 i 1 父節點i的右子節點在位置 2 i 2 子節點i的父節點在位置 floor i 1 2 堆中的最大值總是位於根節點。堆中定義以下幾種操作 1 最大堆調整 max he...
排序七 堆排序
時間複雜度 最好 o n o n 平均o n o nlogn 最差o n o nlogn 空間複雜度 o n o 1 穩定性 不穩定 堆 順序儲存的完全二叉樹,其每個結點均小於等於或大於等於其子節點。小根堆 每個結點元素的值都小於等於其子節點元素的值的堆。s i s 2 i 1 s i s 2 i ...