【八大经典排序算法】堆排序

【八大经典排序算法】堆排序


一、概述

堆排序是J.W.J. Williams于1964年提出的。他提出了一种利用堆的数据结构进行排序的算法,并将其称为堆排序。堆排序是基于选择排序的一种改进,通过维护一个堆来选择最大(或最小)的元素,并将其放置在数组的末尾,然后对剩余的元素进行递归调用堆排序。

堆排序在其初期的版本中存在一些性能问题,例如在构建堆的过程中需要频繁的调整堆的结构,导致性能的下降。为了改进这个问题,人们提出了一种称为"堆调整"的操作,将调整堆的过程优化为一次遍历,从而提高了性能。此外,还有一些其他的改进方法,如使用二叉堆来代替普通堆,使用自底向上的构建堆的方法等。

堆排序作为一种经典的排序算法,经过多年的发展与改进,已经成为一种高效稳定的排序算法,并在实际应用中得到广泛的应用。


二、思路解读

我们知道堆排序是一种基于堆数据结构的排序算法,所以堆排序分为以下几步:

①:构建大堆(或小堆)。这里我们从数组的最后一个数据的父节点开始,采用向下调整算法来建堆。

向下调整算法有一个前提:左右子树必须是一个堆,才能调整。同时还要注意是调大堆还是小堆。
调小(大)堆:堆顶元素和孩子中最小(大)的节点比较,如果父节点大于(小于)较小的子节点子,两者交换。不断向下调整到合适位置。(调大堆,和较大孩子比较)

②:将堆中最大(或最小)的元素即堆顶元素与数组中最后一个元素交换位置,然后将堆的大小减1。将交换后的堆顶元素进行向下调整,直到堆再次满足堆性质。

③: 重复上述步骤,直到堆的大小为1,此时整个数组就有序了


三、代码实现(大堆为例)

c 复制代码
void AdjustDown(int* a, int n, int parent)
{
	//建大堆
	int child = parent * 2 + 1;

	while (child < n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}

		if (a[parent] < a[child])
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//堆排序
void HeapSort(int* a, int n)
{
	//升序,建大堆
	for (int i = (n - 2) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}

	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}

时间复杂度:O(N*logN)
空间复杂度:O(1)


相关推荐
Dicky-_-zhang4 分钟前
日志管理实战:ELK与Loki对比选型与落地实践
java·jvm
nJI74egg120 分钟前
JavaEE初阶---《JUC 并发编程完全指南:组件用法、原理剖析与面试应答》
java·面试·java-ee
刮风那天28 分钟前
Android AMS创建进程不用Binder而用Socket?
android·java·binder
小王C语言29 分钟前
【线程概念与控制】:线程封装
jvm·c++·算法
程序员老邢34 分钟前
【技术底稿 37】Spring Boot 3.x 自动装配 “死锁” 排查:3 个注解实现条件化装配与 Mock 兜底
java·spring boot·后端·自动装配·rag·技术底稿
学习,学习,在学习35 分钟前
Qt工控仪器程序框架设计详解(工控多仪器控制版本)
开发语言·c++·qt
kyle~37 分钟前
工程数学---点云配准卡布施(Kabsch)算法(求解最优旋转矩阵)
线性代数·算法·矩阵
三品吉他手会点灯41 分钟前
C语言学习笔记 - 35.数据类型 - printf函数的非输出控制符与格式优化
c语言·开发语言·笔记·学习
日月云棠1 小时前
JAVA数据结构与算法 - 基础:链表
java·后端
张二娃同学1 小时前
03_变量常量与输入输出_printf与scanf详解
算法