資料結構 堆以及堆排序

2021-10-05 21:14:00 字數 3853 閱讀 2727

首先要明確一點,堆並不是我們直接寫好的,是需要建立堆,即根據一種演算法,把不是堆的一組資料變成大根堆或者小根堆,還是上述的圖我們可以知道這個堆的順序是100,90,85,72,71,65,79,52,56,45,58。當然,這個堆的順序存在多個,只要滿足根節點和孩子節點之間的關係就行,所以堆不是唯一的。

接下來,我們看一下建立乙個大根堆需要哪些資料型別以及函式介面

#include

#include

#include

typedef

int hpdatatype;

//資料型別

typedef

struct heap //堆這個結構體

heap;

//交換函式

void

swap

(hpdatatype* array,

int a,

int b)

void

shiftdownbig

(hpdatatype* array,

int size,

int parent)

;//大堆向下調整

void

shiftupbig

(hpdatatype* array,

int child)

//大堆向上調整

void

heapcreat

(heap* hp,hpdatatype* arry,

int size)

//建立堆

void

(heap* hp,hpdatatype data)

//向堆中插入乙個資料

void

(heap* hp)

//堆中刪除最值

hpdatatype heaptop

(heap* hp)

//獲取堆頂元素

intheapisempty

(heap* hp)

//判斷堆是否為空

在建立堆之前,我們需要了解一下什麼是大堆向下調整。

顧名思義,每一次向下調整成乙個大堆,那麼我們就需要找到這組資料的最後乙個非葉子結點,來調整。我們預設葉子節點是有序的,則需要從這個葉子節點的父節點開始向下判斷,如果不是大堆,則需要與兩個孩子的最大值進行交換,依次向上判斷,直至變成乙個大根堆。

建立堆hp是指向這個堆的根節點的指標,hpdatatype* array則是給你的那組資料,你要將它變成乙個大根堆,即要將這個資料複製到hp所指向的那個記憶體空間

void

heapcreat

(heap* hp,hpdatatype* array,

int size)

}

大堆向下調整上面已經說過什麼是大堆向下調整,這裡我們仔細的來看。如下圖

很明顯這不是乙個大根堆,那麼我們是如何調整呢?

首先我們找到最後乙個非葉子結點,發現是90,那麼從這裡向下判斷是否為乙個大根堆呢?顯而易見這是乙個大根堆,因為90大於45和71,像上乙個走,到了56,此時發現這不是乙個大根堆,因為72是大於56的,所以這裡調整一下,讓72與56交換得下圖

此時72這個結點向下看為乙個大根堆,調整好後繼續向上走,走到85,發現該結點向下看去是乙個大根堆,則繼續走,走到58,發現這不是乙個大根堆,則從兩個孩子中選出最大的和58交換,顯然90是最大的,交換得下圖

可是這裡發現,雖然90的確比他的兩個孩子大,但是一交換後,58這個結點又不是他的孩子中最大的,這裡怎麼辦呢?很簡單,當90這個結點交換後,我們只需要繼續向下走,判斷它的兩個孩子是否還滿足大根堆的要求,如果不滿足,則繼續交換。交換後就得到下圖

到這裡我們發現所有結點都滿足大根堆的條件了,也相當於這個大根堆建立好了

**實現如下

void

shiftdownbig

(hpdatatype* arry,

int size,

int parent)

else

break

;//不需要調整跳出迴圈

}}

大堆向上調整如果向已經建好的乙個大根堆中插入乙個資料,則需要通過大根向上調整來重新調整好乙個新的堆與大堆向下調整思路類似,但值得注意的是大堆向上調整是從最後乙個孩子結點判斷是否滿足大根堆的條件,依次類推

//引數傳入的是孩子

void

shiftupbig

(hpdatatype* arry,

int child)

else

break

;//不需要調整跳出迴圈

}}

堆中插入資料在已建好的堆中插入乙個資料,最好辦法就是尾插,即插入到堆的最後乙個為止,並且使size++,然後來一次大根堆向上調整即可

void

(heap* hp,hpdatatype data)

hp->array[hp->size++

]= data;

//做一次向上調整,這裡直接傳入該堆的最後乙個結點下標即可

shifupbig

(hp,hp->size -1)

;}

堆中刪除最值我們建立好堆,刪除什麼值意義最大呢?很顯然,刪除堆中的最值意義最大,那麼我們能直接刪掉嗎?如果直接刪掉,那麼這個堆便沒有根節點,什麼也不是了,所以我們需要換一種刪除方法。我們可以將根節點與最後乙個結點交換,再通過尾刪,將最值刪除後,同時走一遍向上調整構成乙個新的堆,這時我們的刪除就結束了。

void

(heap* hp)

獲取堆頂元素

hpdatatype heaptop

(heap* hp)

判斷堆是否為空

int

heapisempty

(heap* hp)

上面已經說過建立堆後,那麼堆排序便已經呼之欲出了。堆排序,即我們每次從大根堆或者小根堆中取出乙個最後,做一次堆的調整,直到該堆為空後,就會得到一組有序的數值,即排序成功。也不難想到通過尾刪的方法來實現堆排序,當然這裡的尾刪是假尾刪。**如下

首先要想堆排序,我們先得建堆,具體怎麼建堆,上面已經說過。

void

heapsort

(int

* array,

int size)

//排序

int end = size -1;

//取最後乙個元素

while

(end>0)

//該迴圈每結束一次,都會將最值放到最後,依次形成乙個有序序列

}

資料結構 堆以及堆排序

堆可以看作是一棵完全二叉樹,除最後一層外,每一層都是填滿的,最後一層從左到右依次填入 在堆上,對任意乙個結點來說,越接近頂部,權值就越大 一般指大頂堆 並且它的權值大於等於它所在子樹所有點的權值 我們把根結點權值大於等於樹中結點權值的稱為大根堆,小於等於樹種結點權值的稱為小根堆 下圖就是乙個大根堆的...

資料結構堆以及堆排序的要點

1 堆 堆的重要性質 任意節點的值總是大於等於 或者小於等於 子節點的值 2 二叉堆 二叉堆的邏輯結構是乙個完全二叉樹 也叫完全二叉堆 鑑於完全二叉樹的一些特性,二叉堆的底層 物理結構 一般用陣列實現 索引 i 的規律,n是元素的數量 3 最大堆的建立 兩種方式 1 自上而下的上慮 2 自下而上的下...

堆(資料結構)及堆排序

這裡的堆是指一種資料結構 或資料結構屬性 非指堆記憶體。堆屬性用二叉樹來體現,具堆屬性的資料結構才可被叫做為堆。具堆屬性的資料結構滿足以下筆記的 順序 和 形狀 兩個條件。將某資料結構如陣列,將陣列的元素依次安排在二叉樹中的根結點 根結點的左孩子 根結點的右孩子位置之上,再將剩餘元素依次安排在根結點...