排序 六 之堆排序

2021-09-30 01:15:07 字數 3177 閱讀 4311

三、維護堆的性質

四、堆排序

五、**示例

六、例項測試

堆也可以說是乙個完全二叉樹,就是除了最底層的,其它層是滿的,既然我們可以用完全二叉樹來表示乙個堆,那麼我們這裡就採用陣列結構的二叉樹來闡述堆的性質。

假設在這裡我們用陣列a表示堆,a[i]表示堆裡面的第i個元素,於是我們通過二叉樹的性質可知:

在堆裡面,我們可以大致將堆分為三類:最小堆、最大堆、堆

只要在二叉樹結構裡面,對於除了根節點意外的任何節點i都滿足:

那麼就稱具有這種性質的堆為最小堆

與最小堆類似,只要在二叉樹結構裡面,對於除了根節點意外的任何節點i都滿足:

那麼就稱具有這種性質的堆為最大堆

對於即不是最小堆也不是最大堆的堆來說,這種對我們就稱之為堆

假如我們改變最大堆裡面的乙個元素的大小,那麼整個最大堆的性質將會被破壞,這裡我們需要找到一種在改變了最大堆或者是最小堆的元素的情況下,進行一定變換就可以保持堆原有性質的方法! 因為最大堆和最小堆基本類似,於是我們在這裡選出最大堆進行講解,我們假設維護最大堆性質的函式為max-heapify(a,i),這裡輸入需要維護的堆a和改變的元素位置i。在堆a進行維護之前,必須保證i節點的左子樹left(i)和右子樹right(i)有最大堆的性質,這一點很重要。

下面我們用偽**實現max-heapify(a,i):

max-

heapify

(a,i)

if i >= a.heapsize

return

leftchild =

leftchild

(i)rightchild =

rightchild

(i);

maxpos = i

if a[leftchild]

> a[i]

: maxpos = leftchild;

if a[rightchild]

> a[maxpos]

: maxpos = rightchild;

if(maxpos == i)

return

;exchange

(a,maxpos,i)

max-

heapify

(a,maxpos)

在諸多的排序演算法裡面裡面,堆排序算是比較快速的了,排序時間消耗為:o(nlogn)o(nlogn),雖然相對於快速排序來說慢了一點點,但是就對於堆的特有性質而言(最大堆堆頂元素為最大元素,最小堆堆頂元素為最小元素),堆還是有比較多的用途的.

假如給定我們乙個陣列a=a=,陣列aa裡面的元素是任意無序的,現在要將這些該陣列進行堆的構建,我們需要怎麼做?因為最大堆和最小堆比較類似,所以我們這裡採用最大堆來講解。

上面提到過乙個維護堆性質的函式max-heapify(a,i)嗎?max-heapify(a,i)這個函式是在節點i的左子樹和右子樹均滿足最大堆的性質下進行的。

但是我們在陣列aa裡面除了葉節點以外,我們都不能保證每一棵子樹都是具有最大堆的性質的,於是我們現在需要從葉節點的父節點開始,自下而上的維護最大堆的性質,因為parent(i)是一定小於i的,所以在我們用max-heapify(a,i)維護節點i的性質的時候,其子樹是一定具有最大堆的性質的,因為其子樹leftchild(i)和rightchild(i)的最大堆性質是早於其父節點i構建的,且其執行時間為o(logn)o(logn)。

給定我們乙個最大堆aa,要我們對這個最大堆進行排序,因為最大堆/最小堆的堆頂元素永遠是整個堆裡面最大/最小的,於是我們不妨將整個堆頂的元素提出來,然後將堆尾部的元素放入堆頂,對堆頂1進行堆性質的維護,之後堆頂元素就成了剩下元素裡面最大的,再次提出該元素,重複上面的動作,直到堆只剩下乙個元素即可,這個就是堆排序的核心思想了。

為了怎麼空間的可重用性,我們不妨將堆頂元素和堆尾部的元素交換,然後讓堆大小減小一,當整個操作完畢後,陣列aa就是已經有序的了!

/*i的父節點,左子節點,右子節點*/

#define parent(i) ((i) >> 1)

#define leftchild(i) ((i) << 1)

#define rightchild(i) (((i) << 1) + 1)

/*交換陣列p1與p2的位置*/

intexchange

(int

*array,

int p1,

int p2)

/*維持最大堆的性質*/

intmaxheapify

(int

*array,

int pos,

int length)

return0;

}int

heap_sort

(int

*array,

int length)

/*下面開始每次都取出堆裡面堆頂位置的元素,再次進行堆性質維護*/

for(i = arraysize; i >=

2; i --

)//array[0] = arraysize;

return0;

}

sort.c

int

main

(int argc,

char

**ar**)

;int buf=

;//int buf[10]=;

length =

sizeof

(buf)

/sizeof

(int);

// shell_sort(buf, length, 2);

// quick_sort(buf, 0, length - 1);

// mergesort(buf, length);

printf

("start heap sort...\n\n");

heap_sort

(buf-

1, length)

;for

(i =

0; i < length; i++

)printf

("%d\t "

, buf[i]);

printf

("\n");

return0;

}

測試結果:

排序之堆排序

堆排序是一種基於比較排序的另一種排序演算法,它採用了一種近似完全二叉樹的二叉堆資料結構。演算法實現相容了插入排序的空間原址性 即只需要有限個額外的儲存空間 和歸併排序的優良時間複雜度。偽 如下 heapsort a build max heap a for i a.length downto 2 e...

排序之堆排序

這裡沒有對0號元素進行排序 堆排 public class heap public static void exec comparable array,int i,int j 下沉 private static void sink comparable array,int k,int n publi...

排序之堆排序

堆其實是一種完全二叉樹,從上到下從左到右,大頂堆的父節點大於其左右子節點,小頂堆的父節點小於其左右子節點 1 首先是進行heapify,建立堆 2 從下到上,從右到左的進行heapify構建有序的堆 3 進行排序,將堆頂父節點和底層最右邊的子節點互換,然後不斷重複以上步驟 1 heapify def...