今天我们不刷力扣了,我们来复习(手撕)一下数据结构中的八大排序算法之一,堆排序
基本概念:
堆是一种特殊的树形数据结构,即完全二叉树。
堆分为大顶堆和小顶堆:
大顶堆:每个节点的值都大于或等于其两个子节点的值,在堆排序算法中用于升序排序。
小顶堆:每个节点的值都小于或等于其两个子节点的值,在堆排序算法中用于降序排序。
映射为数组:
代码实现:
//堆排序public static void heapSort(int[] arr) {//构造大根堆heapInsert(arr);int size = arr.length;while (size > 1) {//固定最大值swap(arr, 0, size - 1);size--;//构造大根堆heapify(arr, 0, size);}}//构造大根堆(通过新插入的数上升)public static void heapInsert(int[] arr) {for (int i = 0; i < arr.length; i++) {//当前插入的索引int currentIndex = i;//父结点索引int fatherIndex = (currentIndex - 1) / 2;//如果当前插入的值大于其父结点的值,则交换值,并且将索引指向父结点//然后继续和上面的父结点值比较,直到不大于父结点,则退出循环while (arr[currentIndex] > arr[fatherIndex]) {//交换当前结点与父结点的值swap(arr, currentIndex, fatherIndex);//将当前索引指向父索引currentIndex = fatherIndex;//重新计算当前索引的父索引fatherIndex = (currentIndex - 1) / 2;}}}//将剩余的数构造成大根堆(通过顶端的数下降)public static void heapify(int[] arr, int index, int size) {int left = 2 * index + 1;int right = 2 * index + 2;while (left < size) {int largestIndex;//判断孩子中较大的值的索引(要确保右孩子在size范围之内)if (arr[left] < arr[right] && right < size) {largestIndex = right;} else {largestIndex = left;}//比较父结点的值与孩子中较大的值,并确定最大值的索引if (arr[index] > arr[largestIndex]) {largestIndex = index;}//如果父结点索引是最大值的索引,那已经是大根堆了,则退出循环if (index == largestIndex) {break;}//父结点不是最大值,与孩子中较大的值交换swap(arr, largestIndex, index);//将索引指向孩子中较大的值的索引index = largestIndex;//重新计算交换之后的孩子的索引left = 2 * index + 1;right = 2 * index + 2;}}//交换数组中两个元素的值public static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
算法思路:
排序步骤:
1.构造一个大顶堆(或小顶堆),取堆顶数字(也就是最大值或最小值)
2.再将剩下的数字构建一个大顶堆(或小顶堆),取堆顶数字(也就是剩下值当中的最大值(或最小值))
3.重复以上操作,直到取完堆中的数字,最后得到一个从大到小(或从小到大)排序的序列
基本思路:
将所有元素构成一个堆的形式,然后比较每一个二叉树,将最大的或最小的与根节点元素互换位置,最后将最顶根节点取出,再从左到右、从下到上的方式将尾节点放到最顶根节点上,再重复上述操作进行排序取出最大或最小元素,以此类推,直到所有元素取出。
平均时间复杂度:O()
学习参考:
堆排序算法(图解详细流程)-CSDN博客