【堆排序】

堆排序

一、基本概念

1、堆排序是一种利用堆这一数据结构来排序的排序算法。堆近似于完全二叉树、有着完全二叉树的性质。

补充

大根堆(大顶堆)与小根堆(小顶堆)介绍
大根堆:任意根值都要大于等于其左右孩子值的堆(完全二叉树)
小根堆:任意根值都要小于等于其左右孩子值的堆

二、基本算法思想

1、先将数组建成一个大根堆(排升序建大根堆,排降序建小根堆),此时堆顶元素是最大值元素。
2、将堆顶元素与数组最后一个元素交换,则最大值已就位(只需把n-1个元素重新调整建堆,已就位的最大值无需参与建堆)。
3、用向下调整算法调整堆(元素交换后已不是大根堆,需要重新调整成大根堆)。
4、再将堆顶元素与数组倒数第二个元素交换,则次大值已就位。再调整堆。。。。
5、依次类推。。。。

思考

1、向下调整算法怎样实现呢?(怎样去把一个堆调整成大根堆呢)
2、我们要怎样去建立一个大根堆呢?

三、算法实现

实现向下调整算法

1、基本介绍
通过从上到下的算法排序,将一个堆变成大根堆或者小根堆。

注意此堆(完全二叉树)的左边堆(根节点的左子树)和右边堆(根节点的右子树)一定要是大根堆(或者小根堆)才行。

2、演示
在这里插入图片描述
3、具体代码

void AdjustHeap(int* arr, int n, int root) {

	int parent = root;
	int child = parent * 2 + 1;
	while (child < n) {//当左右孩子都不存在时跳出
		if (child+1 < n && arr[child] < arr[child + 1]) {//注意有可能右孩子不存在
			child += 1;
		}
		if (arr[child] > arr[parent]) {
			Swap(&arr[child], &arr[parent]);//交换两数
			parent = child;
			child = parent * 2 + 1;
		}
		else {
			break;
		}
	}
}

建大根堆

在这里插入图片描述

寻找非叶子节点的第一个根节点
最后一个叶子节点下标为n-1(n为数组元素个数),则其父母节点为(n-2)/2
根据完全二叉树性质得来

//建大根堆
	for (int i = (n - 2)/2; i >= 0; i--) {
		AdjustHeap(arr, n, i);//向下调整算法
	}

四、整合得堆排序

堆排序:
1.建大根堆(排升序)
2.把最后一个元素与堆顶元素交换(此时最大元素已经就位,只需排n-1个元素)
3.向下调整算法调整好堆
4.把倒数第二个元素与堆顶元素交换,调整好堆。。。。。依次类推

void AdjustHeap(int* arr, int n, int root) {

	int parent = root;
	int child = parent * 2 + 1;
	while (child < n) {//当左右孩子都不存在时跳出
		if (child+1 < n && arr[child] < arr[child + 1]) {//注意有可能右孩子不存在
			child += 1;
		}
		if (arr[child] > arr[parent]) {
			Swap(&arr[child], &arr[parent]);//交换两数
			parent = child;
			child = parent * 2 + 1;
		}
		else {
			break;
		}
	}
}

void HeapSort(int* arr, int n) {
	//建大根堆
	for (int i = (n - 2)/2; i >= 0; i--) {
		AdjustHeap(arr, n, i);//向下调整算法
	}
	//最后一个元素与堆顶元素交换(此时最大元素已经就位,只需排n-1个元素)
	int end = n-1;
	while (end>0) {
		Swap(&arr[end], &arr[0]);//交换完大根堆已被破环,需调整
		AdjustHeap(arr, end, 0);//调整再次变成大根堆
		end--;
	}
}

五、时间复杂度计算

堆排序主要有两步:1、把数组建成一个大根堆 2、向下调整算法调整堆

1、建大根堆
该建堆方式是从倒数第二层的节点(叶子节点的上一层)开始,从右向左,从下到上的运用向下调整算法进行调整,而建成的。

当n很大时,可以把完全二叉树近似为满二叉树。考虑到最坏的情况:
第一层的一个节点向下调整了h-1次;
第二层的二个节点都向下调整了h-2次;
第三层的四个节点都向下调整了h-3次;
。。。。

所以时间复杂度t(n)=1*(h-1)+2*(h-2)+…+2^(h-2)*1
用高中的错位相减法得出时间复杂度结果为O(n);

2、向下调整算法调整堆
最多调整完全二叉树高度次。
所以时间复杂度为O(logN);

所以堆排序时间复杂度为O(N*logN)。堆排序是一种很优秀的算法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值