前言
堆排序也是一种非常重要的排序算法,但是在写堆排序算法之前,需要对堆的概念有一定了解,简单来说就是利用了大根堆和小根堆的特性,在大根堆中,堆顶的元素是整个堆元素中最大的,小根堆中,堆顶的元素是整个堆元素中最小的。
原理
其实原理简单点说,就是利用大根堆小根堆的性质,那么怎么根据大根堆小根堆的性质来实现排序的效果呢?
第一步,建堆,如果为升序,建大根堆,为降序,建小根堆。怎么将一个有序数组构建成一个堆呢?首先根据堆的特点,我们可以从堆的长度中心位置,也就是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);
}
}
}
下一篇:归并排序
入口在此:点我学习归并排序