堆排序(heap sort):建堆,將最大值/最小值放到對應的位置上。
我們看堆排序以前,先回憶一下完全二叉樹有一條性質,如果將一顆完全二叉樹從0開始編號(從上到下,從左到右),結點編號i為0到n-1,如果滿足2 i + 1 <= n - 1,則證明有左,滿足2 i +2 <= n - 1,則證明有右,父親結點的範圍為0到 n / 2 - 1。那這與堆排序又有什麼關係呢?堆的內部就是遵循以上邏輯關係的。注意:堆內部只是遵循完全二叉樹所有的這條性質的邏輯關係,並非是一棵樹,它的本質仍是陣列。
待排資料為:8、12、19、1、14、7、20、6。這組資料並非是堆。我們先將這組資料按照邏輯結構化成二叉樹的樣子。
堆分為兩種,大根堆(三者父親最大):所有的父親結點的值都大於其左右結點,小根堆(三者父親最小)剛好反過來,所有根節點都小於其左右結點,並且不管是大根堆還是小根堆,左右兄弟結點是不存在比較關係的,只有父親和孩子之間存在比較關係。
我們要先將堆建出來,建乙個大堆。從最下面最後乙個父親結點1開始,6沒有兄弟,1與左孩子6比,1比6小,二者交換。7與20比,20大,19與20比,20大,19與20交換,6與14比,14大,12與14比,14大,12與14交換,14與20比,20大,8與20比,20大,8與20交換,然後根的右結點已經調整過了,但是在調整完上面以後,他就不符合大堆的性質,需要再調,7和19比,19大,8和19比,19大,8與19交換。這時候大堆就算建完了為:20、14、19、6、12、7、8、1。
這時候大堆就算建完了為:20、14、19、6、12、7、8、1。
我們現在已經建完堆(初始堆)了,需要把最大/最小元素放到對應的位置上去,因為剛剛我們建的是大堆,所以堆頂一定是最大值。最大值要放在最後面,20與1交換,20沒有必要在參與接下來的操作,剩餘1、14、19、6、12、7、8。經過交換以後這已經不是大堆了,14與19比,19大,1與19比,19大,19與1交換,7和8比,8大,1和8,8大,1與8交換。
堆變成19、14、8、6、12、7、1。同理第二大元素19,19和1發生交換。剩餘1、14、8、6、12、7;接著重複以上操作。
大堆為:14、12、8、6、1、7,第三大元素14,與倒數第三個元素發生交換,剩餘7、12、8、6、1。
大堆為:12、7、8、6、1;第四大元素12,與倒數第4個元素交換;剩餘1、7、8、6。
大堆為:8、7、1、6,第五大元素8與倒數第五個元素6發生交換;剩餘6、7、1。
大堆為:7、6、1,堆頂7與當前最後操作元素1交換;剩餘1、6。
大堆為:6、1,堆頂6與當前最後操作元素1交換;剩餘1,結束。
排序完成:20、19、14、12、8、7、6、1。
#
include
#define
left(2
*nrootid +1)
#define
right(2
*nrootid +2)
//堆排
void
adjust
(int arr,
int nlength,
int nrootid)
else
}else
else}}
//乙個孩子
else
if(left < nlength)
else
}//0個孩子
else}}
void
heapsort
(int arr,
int nlength)
for(i = nlength-
1;i >
0;i--)}
void
printf
(int arr,
int nlength)
}int
main()
;heapsort
(arr,
sizeof
(arr)
/sizeof
(arr[0]
));printf
(arr,
sizeof
(arr)
/sizeof
(arr[0]
));printf
("\n");
return0;
}
堆排優化:
調整的三段**都是孩子裡大的與父親進行比較,然後如果較大的孩子比父親大,二者就發生交換。那我們一開始來的時候就找到較大的孩子賦值給max,接下來讓max與父親進行比較。
void
adjust2
(int arr,
int nlength,
int nrootid)
}//大的和父親比較
if(arr[max]
> arr[nrootid]
)else
}}
經典排序演算法之堆排序
堆排序是一種選擇排序,是不穩定的排序方法。特點 在排序過程中,將排序陣列看成是一棵完全二叉樹儲存結構,利用完全二叉樹中父節點和孩子節點之間的內在關係,在當前無序區中選擇關鍵字最大 最小 的記錄。基本思想 堆分大根堆和小根堆,大根堆是父節點比所有子節點都大,小根堆是父節點比所有子節點都小。下面以大根堆...
經典排序演算法之堆排序
經典排序演算法之堆排序 若以公升序排序說明,把陣列轉換成最大堆積 max heap heap 這是一種滿足最大堆積性質 max heap property 的二叉樹 對於除了根之外的每個節點i,a parent i a i 重複從最大堆積取出數值最大的結點 把根結點和最後乙個結點交換,把交換後的最後...
經典排序之堆排序詳解
首先我們來看看什麼叫做堆排序?若在輸出堆頂的最小值之後,使得剩餘的n 1個元素的序列重新又構成乙個堆,則得到n個元素中的次小值,如此反覆,便能得到乙個有序序列,稱這個過程為堆排序。再來看看總結一下基本思想 將無序序列建成乙個堆 輸出堆頂的最小 大 值 使剩餘的n 1個元素又調整成乙個堆,則可得到n個...