算法导论学习笔记(三):堆排序

堆排序是一种利用堆的性质进行的排序算法。所以学习堆排序之前先来简单介绍下堆。

堆数据结构是一种数组对象,如图一所示,它可以被视为一颗完全二叉树。


     图一

树中的每个结点与数组中存放该结点值的那个元素对应。树的每一层都是填满的,最后一层可能除外。如果树的结点

数组的下标都从0开始,那么给定了某个结点的下标i,其父节点PARENT(i)、左儿子LEFT(i)和右儿子RIGHT(i)的下

标可以简单的计算出来:

PARENT(i) = (i - 1) / 2;注:右边的结果取整数部分

LEFT(i) = 2 * i + 1;

RIGHT(i) = 2 * (i + 1);

最大堆和最小堆

这是堆排序中要用到的两种堆,它们的结点内的数值都要满足堆特性,其细节则由堆的种类而定。在最大堆中,最大

堆特性是指除了根意外的每个结点i,有a[PARENT(i)] >= a[i],即某个结点的值至多是和其父节点的值一样大。这样,

堆中的最大元素就存放在根结点中;并且,在以某一个结点为根的子树中,各结点的值都不大于该子树根节点的值。

最小堆的组织方式则刚好相反。在堆排序算法中,我们一般使用的是最大堆。

堆排序思想

1.将输入的数组构造出一个最大堆,并求出堆的大小heap_size = n

2.将堆顶元素a[0]和最后一个元素a[heap_size - 1]交换

3.堆的大小减小1,即heap_size = heap_size - 1

4.因为调整了堆的大小和交换了元素,所以新的堆可能不满足最大堆的特性,所以对新的堆进行调整,使其再次满足

   最大堆的特性。实现这个调整的函数为:max_heapify

5.重复步骤2、3、4,直到堆只剩下最后一个元素

实现代码

#include<iostream>
using namespace std;

int heap_size;

inline int LEFT (int i)
{
	return 2 * i + 1;
}

inline int RIGHT (int i)
{
	return 2 * (i + 1);
}

void display (int a[], int n);
void swap (int& n, int& m);
void max_heapify (int a[], int i);
void bulid_max_heap (int a[], int n);
void heap_sort (int a[], int n);

int main()
{
	int a[100];
	int n;
	while (cin >> n)
	{
		for (int i = 0; i < n; i++)
			cin >> a[i];
		heap_sort (a, n);
		display (a, n);
	}
	return 0;
}

void display (int a[], int n)
{
	for (int i = 0; i < n; i++)
		cout << a[i] << " ";
	cout << endl;
}

void swap (int& n, int& m)
{
	int temp;
	temp = n;
	n = m;
	m = temp;
}

void max_heapify (int a[], int i)
{
	int l = LEFT (i);
	int r = RIGHT (i);
	int largest;

	if ((l < heap_size) && a[l] > a[i])
		largest = l;
	else
		largest = i;

	if ((r < heap_size) && a[r] > a[largest])
		largest = r;

	if (largest != i)
	{
		swap (a[largest], a[i]);
		max_heapify (a, largest);
	}
}

void build_max_heap (int a[], int n)
{
	heap_size = n;
	for (int i = (n - 1) / 2; i >= 0; i--)
		max_heapify (a, i);
}

void heap_sort (int a[], int n)
{
	build_max_heap (a, n);
	for (int i = n - 1; i >= 1; i--)
	{
		swap (a[i], a[0]);
		heap_size--;
		max_heapify (a, 0);
	}
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值