数据结构之堆排序

堆排序:

1.堆的概念

堆其实就是一颗完全二叉树,关于什么是完全二叉树在二叉树的基本概念中有说明,在这就不细说了。

2.堆的分类

堆分为小堆和大堆。

  1. 小堆:父节点都不大于任意直接子节点。
  2. 大堆:父节点都不小于任意直接子节点。

举例来说,对于n个元素的序列{R0, R1, … , Rn}当且仅当满足下列关系之一时,称之为堆:

(1) R[i] <= R[2i+1] 且 R[i]<= R[2i+2] (小根堆)

(2) R[i] >= R[2i+1] 且 R[i] >= R[2i+2] (大根堆)

其中i=1,2,…,n/2向下取整;

下图为一小堆图:

在这里插入图片描述
如上图所示,序列R{3, 8, 15, 31, 25}是一个典型的小根堆。

堆中有两个父结点,元素3和元素8。

元素3在数组中以R[0]表示,它的左孩子结点是R[1],右孩子结点是R[2]。

元素8在数组中以R[1]表示,它的左孩子结点是R[3],右孩子结点是R[4],它的父结点是R[0]。可以看出,它们满足以下规律:

设当前元素在数组中以R[i]表示,那么,

(1) 它的左孩子结点是:R[2*i+1];

(2) 它的右孩子结点是:R[2*i+2];

(3) 它的父结点是:R[(i-1)/2];

(4) R[i] <= R[2*i+1] 且 R[i] <= R[2i+2]。

3.实现过程

假如将堆的元素存储在一个数组中,我们可以这样理解:

  1. 首先,按堆的定义将数组R[0…n]调整为堆(这个过程称为创建初始堆),然后交换R[0]和R[n];
  2. 将R[0…n-1]重新调整为堆,交换R[0]和R[n-1];
  3. 如此反复,直到交换了R[0]和R[1]为止。

下面以大堆为例说明:

按以上思路可归纳为两个操作:

(1)根据初始数组去构造初始堆(构建一个完全二叉树,保证所有的父结点都不小于它的孩子结点数值)。

(2)每次交换第一个和最后一个元素,输出最后一个元素(最大值),然后把剩下元素重新调整为大根堆。

当输出完最后一个元素后,这个数组已经是按照从小到大的顺序排列了。

先通过详细的实例图来看一下,如何构建初始堆。

设有一个无序序列 { 1, 3, 4, 5, 2, 6, 9, 7, 8, 0 }。
在这里插入图片描述

构造了初始堆后,我们来看一下完整的堆排序处理:

还是针对前面提到的无序序列 { 1, 3, 4, 5, 2, 6, 9, 7, 8, 0 } 来加以说明。
在这里插入图片描述
相信通过上面两幅图大家对堆的构造和排序过程已经清楚。

4.算法实现

#include<iostream>

void swap( int* p1, int* p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

/************************************************
function:调整堆
length:需要调整的数组元素的个数
******************************************************/
void adjustHeap(int* arr,int length)
{
	if (length <= 1)
	     return;
	for (int j =  length/2; j >=0; --j)
	{
	       //左右子节点都存在时
		if (2 * j + 2 <= length-1)
		{
			int max_index = 0;
			if (arr[2 * j + 1] < arr[2 * j + 2])//左右子节点比较
			{
				max_index = 2 * j + 2;     //右节点的下标
			}
			else
				max_index = 2 * j + 1; //左节点的下标
			if (arr[j] < arr[max_index])  
			 swap(&arr[j], &arr[max_index]);//交换父节点与最大子节点的值
			continue;
		}
              //只有左子节点时
		if (2 * j + 1 < length)
		{
		    if (arr[j] < arr[2 * j + 1])
			  swap(&arr[j], &arr[2 * j + 1]);
		}
	}
}

/*********************************************************
function:排序
********************************************************/
void heap_sort(int* arr, int length)
{
	if (length <= 1)
		return;
	adjustHeap(arr, length);//建堆
	swap(&arr[0], &arr[length - 1]);//交换第一个与最后一个元素
	length -= 1;
	heap_sort(arr, length); //递归调用
}

//主函数
int main()
{
	int arr[10] = { 1,5,85,14,56,9,45,20,30,2 };
	heap_sort(arr,10);
	for (int i = 0; i < 10; i++)
		std::cout << arr[i] << " ";
	system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值