堆结构与堆排序

堆结构

堆是一棵特殊的完全二叉树,树中的节点满足一定的性质,根据性质的不同,堆有两种:

  • 大根堆
  • 小根堆

虽然堆是用完全二叉树表示的,但在使用时通常用一个数组来存储。以数组的下标来标识堆中的节点,并且可以根据下标来获得某一节点的父节点和左右子节点。

对于下标为i的节点,其父节点为(i - 1) / 2,其左子节点为2 * i + 1,右子节点为2 * i + 2。

我们定义一个节点的高度为从该节点到叶子节点的最长简单向下路径的边数。树的高度就是根节点的高度。对于具有n个元素的数组,将其看作完全二叉树的话,树的高度为lgn。

txt 复制代码
arr = { 1, 2, 3, 4, 5, 6, 7 }

            1
        2       3
     4    5   6   7

同时可以看到,对于大小为n的堆,n/2为该堆的第一个叶子节点。

大根堆

对于任意一个节点来说,它的值都比其子节点的值大。

txt 复制代码
            7
        6       5
     4     3  2   1

堆的调整

在讲如何构建堆之前,先讲讲堆的调整操作。以大根堆为例。

对于堆中的一个节点来说,调整的方式有两种:向上调整和向下调整。

什么是向上调整?对于节点i来说,以i为根的子树已经满足了大根堆的性质,但是i之上的节点不一定满足大根堆的性质。向上调整将i与其父节点作比较,如i节点的值比父节点大,则交换i和父节点。如此重复,直到i比父节点小或者i为根节点。

cpp 复制代码
#define PARENT(i)	((i - 1) / 2)
#define LEFT(i)		(2 * i + 1)
#define RIGHT(i)	(2 * i + 2)

static void swap(int* arr, int i, int j)
{
	arr[i] += arr[j];
	arr[j] = arr[i] - arr[j];
	arr[i] = arr[i] - arr[j];
}

//堆的插入操作,向上调整,将i位置的节点调整至符合大根堆性质的位置
static void MaxHeapInsert(int* arr, int i)
{
	int p = PARENT(i);
	if (p >= 0 && arr[i] > arr[p])
	{
		swap(arr, i, p);
		MaxHeapInsert(arr, p);
	}
}

了解了向上调整,向下调整就很好理解了:

cpp 复制代码
//向下调整。
static void MaxHeapfiy(int* arr, int size, int i)
{
	int l = LEFT(i);
	int r = RIGHT(i);

	int largest;
	if (l < size && arr[l] > arr[i])
		largest = l;
	else largest = i;

	if (r < size && arr[r] > arr[largest])
		largest = r;

	if (largest != i)
	{
		swap(arr, i, largest);
		MaxHeapfiy(arr, size, largest);
	}
}

构建大根堆

假如现在有一个数组,我们希望把它变为大根堆的形式,该如何做到?

很简单,我们只需要遍历数组,对每个节点都进行向上调整即可:

cpp 复制代码
static void BuildMaxHeap(int* arr, int size)
{
	for (int i = 0; i < size; i++)
		MaxHeapInsert(arr, i);
}

小根堆

了解了大根堆及其调整方法之后,小根堆的调整和构建自然不是问题。

堆排序

我们现在有一个无序数组,我们可以利用堆的性质来对其进行排序。以从小到大排序为例,我们使用了大根堆。

堆排序步骤如下:

  1. 将数组构建为大根堆
  2. 将堆顶元素和堆最后一个叶子节点交换
  3. 堆的大小减一
  4. 维护大根堆
  5. 重复1到4的步骤直到堆的大小为1
cpp 复制代码
static void HeapSort(int* arr, int size)
{
	BuildMaxHeap(arr, size);
	int heap_size = size;
	while (heap_size != 1) //注意终止条件
	{
		swap(arr, 0, heap_size - 1); //将最大值与末尾元素交换
		printArr(arr, size);
		heap_size--; //调整堆的大小
		MaxHeapfiy(arr, heap_size, 0); //维护大根堆的性质
	}
}
相关推荐
地平线开发者14 小时前
【模型轻量化专题】衡量模型轻量性的指标
算法
学习星球17 小时前
OFDM技术精讲:正交性推导、循环前缀原理与80行Python链路仿真(附实测数据)
算法·面试·前端框架
alphaTao1 天前
LeetCode 每日一题 2026/8/24-2026/8/30
python·算法·leetcode
Interview Aid1121 天前
TikTok OA 四题分享|半小时内 AC,题目基本都是实现题
java·开发语言·算法·面试·职场和发展
顶点多余1 天前
那些在算法中适合巩固的知识点---1
java·前端·算法
AI情绪识别开源1 天前
检信 ALLEMOTION OS 加密打包可执行程序 — 全面测试报告版本: v1.3功能测试 / 性能测试 /
开发语言·数据结构·人工智能·功能测试
罗西的思考1 天前
【Agentic RL / 强化学习框架】Molt 设计解读
人工智能·算法·机器学习
hahaha60161 天前
HLS高层次综合设计技巧--C++类和模板
图像处理·人工智能·算法·计算机视觉
多弗朗皮卡丘1 天前
算法详解4:买卖股票的最佳时机系列(上)
算法
维克兜率天2 天前
【维克】动量指标家族:RSI、ROC、CCI、Momentum全面解析
python·算法