堆和堆排序

堆的定义

1、堆一定是完全二叉树(除了最后一层,其他层一定是满的)
2、堆分为“大根堆”、“小根堆”,“大根堆”的父节点一定大于叶子节点,“小根堆”的父节点一定小于叶子节点。

堆一般使用数组来存储,节省空间,可以不用存储左右子节点,从下标为1的数组开始,可以直接通过根节点 * 2 和 *2 + 1来访问。

建堆

建堆有两种方式,
第一种是从第一个父节点开始,不断往上堆化,直到根节点

void swapArr(int a[], int i, int j) {
	int temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}

void Heapify(int a[], int i, int n) {
	while (true) {
		int max = i;
		if (max * 2 <= n && a[max] < a[i * 2]) max = i * 2;
		if (max * 2 + 1 <= n && a[max] < a[i * 2 + 1]) max = i * 2 + 1;
		if (max == i)break;
		swapArr(a, max, i);
		i = max;
	}
}

void BuildHeap(int a[], int n) {
	for (int i = n / 2; i >= 1; --i) {
		Heapify(a, i, n);
	}
}

第二种是将第一个数作为堆,然后不断往堆尾插入数据,然后从下往上堆化,直到最后一个叶子节点,代码如下。

void InsertBuildHeap(int a[], int n) {
	for (int i = 2; i <= n; ++i) {
		while (i / 2 > 0 && a[i] > a[i / 2])
		{
			swapArr(a, i, i / 2);
			i = i / 2;
		}
	}

}

堆的插入

首先将数据插入堆尾,然后自下而上堆化,参考第二种建堆方式。

删除堆顶

我们首先将堆尾数据覆盖掉堆顶数据,然后自上而下堆化

堆排序

如果前面的建堆和删除堆顶理解了后,堆排序也就很简单了,每一次堆化1到n的数据后,最大值或最小值都在根节点,将根节点和堆尾节点交换,然后继续堆化1到n-1的数据,一直到根节点结束。

void HeapSort(int a[], int n) {
	BuildHeap(a, n);
	int k = n;
	while (k > 1) { 
		swapArr(a, 1, k);
		--k;
		Heapify(a, 1, k);
	}
}

复杂度分析

1、建堆过程的时间复杂度是 O(n),排序过程的时间复杂度是 O(nlogn),堆排序整体的时间复杂度是 O(nlogn)。
2、排序过程中只涉及交换操作,生成常量的空间,所以是原地排序。
3、在排序过程中,每一次会将最后一个数据与第一个数据相交换,所以是不稳定排序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值