堆(heap)排序算法

堆排序算法是复杂的排序算法,是不稳定的排序算法。

1、堆排序的基本思想

堆排序定义:n个有序列A1,A2,...,An成为堆,有下面两种不同类型的堆。

大根堆:所有子节点都大于其父节点,即Ai<=A2i且Ai<=A2i+1。

小根堆:所有子节点都小于其父节点,即Ai>=A2i且Ai>=A2i+1。

若将此序列所存储的向量A[1...n]看为一颗完全二叉树的存储结构,则对实质上是满足如下性质的完全二叉树:树中任一非叶子结点的关键字均不大于(或者不小于)其左、右子节点(若存在)的关键字。

因此堆排序(HeapSort)是树形选择排序。在排序过程中,将R[1...n]看成一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子节点之间的内在的关系,在当前无序区中选择关键字最大的(最小的)记录。

用大根堆排序的基本思想:

(1) 先将初始A[1...n]建成一个大根堆,此堆为初始化无序区。

(2) 再将关键字最大的记录A[1](堆顶)和无序区的最后一个记录A[n]交换,由此得到新的无序区A[1...n-1]和有序区A[n],且满足A[1...n-1] <= A[n].

(3) 由于交换后新的根A[1]可能违反堆性质,所以将当前无序区A[1...n-1]调整为堆。然后再次将A[1...n-1]中关键字最大的记录A[1]和该区间的最后一个记录A[n-1]交换,由此得到新的无序区A[1...n-2]和有序区A[n-1...n],且仍满足关系A[1...n-2] <= A[n-1...n],同样要将A[1...n-2]调整为堆。

(4) 对调整的对重复进行上面的交换,直到无序区只有一个元素为止。


2、思想

利用完全二叉树中双亲节点和孩子节点之间的内在关系,在当前无序区中选择关键字最大(或者最小)的记录。也就是说,以最小堆为例,根节点为最小元素,较大的节点偏向于分布在堆底附近。

3、算法复杂度

最坏情况下,接近于最差情况下:O(N*logN),因此它是一种效果不错的排序算法。

4、稳定性

堆排序需要不断地调整堆,因此它是一种不稳定的排序!

5、代码实现

//编程实现堆排序
//堆排序是较为复杂的排序。
//1.首先是将整个数组进行一个初始化堆操作,是将所有的节点进行堆化(所有的父节点都是自己左右子节点中最大的)
//2.进行堆化之前首先是记录一下堆化的大小(heapSize=len),确定整个数组最后一个父节点(i=len>>1),从最后一个父节点进行遍历到0最顶的父节点(i>=0,i--)
//3.堆化中,首先确定左右子节点索引,largest记录的是左右节点中最大元素的索引,前提条件为:左右子节点索引小于heapSize的(不然没有意义)
//4.先比较左节点与父节点array[left] > array[index]找出最大值赋值给largest,再比较array[right] > array[largest]找到三者最大值
//5.若父节点不是最大值,则交换父节点与largest的位置,在递归进行堆化。直到整个二叉树完全符合大根堆
//6.完成堆化之后,交换最后一个数与堆顶的位置,堆大小-1,在重新在最顶端进行堆化(maxHeapify(array,0))
//7.重复3-7步骤,完成堆排序。
#include<iostream>
using namespace std;

static int heapSize = 0;
//返回左子节点索引
int Left(int index) { return (index << 1) + 1; }
//返回右子节点索引
int Right(int index) { return (index << 1) + 2; }
//交换a、b的值
static void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; }
//array[index]与其左、右子树进行递归对比
//用最大主替换array[index],index表示堆顶索引
void maxHeapify(int array[], int index)
{
	int largest = 0;		//最大值索引
	int left = Left(index);	//左子节点索引
	int right = Right(index);//右子节点索引
	//把largest复位堆顶与其左子节点的较大者
	if ((left <= heapSize) && (array[left] > array[index]))
	{
		largest = left;
	}
	else
	{
		largest = index;
	}
	//把largest与堆顶的柚子节点比较,去较大者
	if ((right <= heapSize) && (array[right] > array[largest]))
	{
		largest = right;
	}
	//此时largest为堆顶、左子节点、右子节点三者中最大者
	if (largest != index)
	{
		//如果堆顶不是最大者,则交换,并递归调整堆
		swap(&array[index], &array[largest]);
		maxHeapify(array, largest);
	}
}
//初始化堆,将数组中的每一个元素只放到适当的位置
//完成之后,最顶的元素为数组的最大值
void buildMaxHeap(int array[], int len)
{
	int i;
	heapSize = len;		//堆大小赋为数组长度
	for (i = (len >> 1); i >= 0; i--)
	{
		maxHeapify(array, i);
	}

}

void heap_sort(int array[], int len)
{
	int i;
	//初始化堆
	buildMaxHeap(array, (len - 1));
	for (i = (len - 1); i >= 1; i--)
	{
		//堆顶元素array[0](数组的最大值)被置换到数组的尾部array[i]
		swap(&array[0], &array[i]);
		heapSize--;				//从堆中移除该元素
		maxHeapify(array, 0);	//重建堆(只有array[0]与array[i]交换,所以重建堆从0开始)
	}
}

void print_array(int a[], int length)
{
	for (int i = 0; i < length; i++)		//打印数据
	{
		cout << a[i] << " ";
	}
}

void main9mianshiti6()
{
	int a[] = { 45, 68, 20, 39, 88, 97, 46, 59 };
	cout << "before heap sort:";
	print_array(a, 8);
	heap_sort(a, 8);
	cout << "\nafter heap sort:";
	print_array(a, 8);
	system("pause");
}

6、测试结果

before heap sort:45 68 20 39 88 97 46 59

after heap sort:20 39 45 46 59 58 88 97

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值