前言
堆排序也是一種非常重要的排序算法,但是在寫堆排序算法之前,需要對堆的概念有一定了解,簡單來說就是利用了大根堆和小根堆的特性,在大根堆中,堆頂的元素是整個堆元素中最大的,小根堆中,堆頂的元素是整個堆元素中最小的。
原理
其實原理簡單點說,就是利用大根堆小根堆的性質,那麼怎麼根據大根堆小根堆的性質來實現排序的效果呢?
第一步,建堆,如果爲升序,建大根堆,爲降序,建小根堆。怎麼將一個有序數組構建成一個堆呢?首先根據堆的特點,我們可以從堆的長度中心位置,也就是list.length/2的位置處,開始構建,然後獲取當前節點、當前節點的左節點、當前節點的右節點中的最大值,並將最大值置於父節點的位置,循環遍歷節點,直到爲0的位置,也就是遍歷到了堆頂的位置,至此,堆建立完畢。
時間複雜度
固定:爲n*logn
代碼
public class HeapSort {
// 堆排序,利用大根堆/小根堆,堆頂元素最大/最小的特點,不斷和堆底元素進行交換,從而排序
// 時間複雜度固定爲 n*Logn
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = new int[] { 8, 5, 0, 7, 3, 1, 2 };
System.out.println("排序前");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
heapSort(arr);
System.out.println("排序後");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void HeapAdjust(int[] array, int parent, int length) {
int child = 2 * parent + 1; // 先獲得左孩子
while (child < length) {
// 如果有右孩子結點,並且右孩子結點的值大於左孩子結點,則選取右孩子結點
if (child + 1 < length && array[child] < array[child + 1]) {
child++;
}
// 如果父結點的值已經大於孩子結點的值,則直接結束
if (array[parent] >= array[child])
// 跳出while循環體
break;
// 交換孩子節點和父節點的值
int t;
t = array[child];
array[child] = array[parent];
array[parent] = t;
// 選取孩子結點的左孩子結點,繼續篩選下一個節點
parent = child;
child = 2 * child + 1;
}
}
public static void heapSort(int[] list) {
// 循環建立初始堆
for (int i = list.length / 2; i >= 0; i--) {
HeapAdjust(list, i, list.length - 1);
}
// 進行n-1次循環,完成排序
for (int i = list.length - 1; i > 0; i--) {
// 最後一個元素和第一元素進行交換
int temp = list[i];
list[i] = list[0];
list[0] = temp;
// 篩選 R[0] 結點,得到i-1個結點的堆
HeapAdjust(list, 0, i);
}
}
}
下一篇:歸併排序
入口在此:點我學習歸併排序