堆结构与堆排序

堆结构

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

  • 大根堆
  • 小根堆

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

对于下标为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); //维护大根堆的性质
	}
}
相关推荐
2***574239 分钟前
人工智能在智能投顾中的算法
人工智能·算法
草莓熊Lotso44 分钟前
《算法闯关指南:动态规划算法--斐波拉契数列模型》--01.第N个泰波拉契数,02.三步问题
开发语言·c++·经验分享·笔记·其他·算法·动态规划
mit6.8247 小时前
bfs|栈
算法
CoderYanger8 小时前
优选算法-栈:67.基本计算器Ⅱ
java·开发语言·算法·leetcode·职场和发展·1024程序员节
jllllyuz8 小时前
Matlab实现基于Matrix Pencil算法实现声源信号角度和时间估计
开发语言·算法·matlab
稚辉君.MCA_P8_Java9 小时前
DeepSeek 插入排序
linux·后端·算法·架构·排序算法
多多*9 小时前
Java复习 操作系统原理 计算机网络相关 2025年11月23日
java·开发语言·网络·算法·spring·microsoft·maven
.YM.Z10 小时前
【数据结构】:排序(一)
数据结构·算法·排序算法
Chat_zhanggong34510 小时前
K4A8G165WC-BITD产品推荐
人工智能·嵌入式硬件·算法