堆排序的实现及优先级队列

文章目录

  • 一   什么是堆
  • 二 堆排序基本思想
  • 三 代码实现
  • 拓展 c++实现优先级队列

一· 什么是堆?

1 堆的定义

堆是一种叫做完全二叉树的数据结构,可以分为大根堆和小根堆(本文使用小根堆完成堆排序)

2 小根堆的定义

图示:

 每个结点的值都小于或等于其左右孩子的值,称为最小堆。每个结点的值都大于其左右孩子的值,称为最大堆。

3 规则

如果有一棵有n个结点的完全二叉树自顶向下,同一层自左向右连续编号为0,1,2,...,n-1,然后按此结点编号将树中各结点顺序的存放在顺序表中(数组)编号为i的结点有一些规则:

(1)若i==0,则i为根结点;若i>0,则i的双亲为(i-1)/2.

(2)若2*i+1<n,则i的左子女为2*i+1;若2*i+2<n,则i的左子女为2*i+2.

(3)若i为偶数且i!=0,则其左兄弟为i-1,;若i为奇数且i!=n-1,则其右兄弟为i+1.

4 物理存储结构

91765234578875331
012345678

二 堆排序基本思想

1 堆排序基本思想(本文为降序排序)

(1)将待排序序列构造为最小堆,此时根节点为整个序列最小值;

(2)将根节点与末尾元素交换,此时末尾为最小值;

(3)接着将剩下n-1个元素重新构造成一个最小堆,可以得到剩下n-1个元素最小值,反复执行此步骤即可完成降序排序.

2 构造小根堆

 给出如下数组

53

1778945658723
01234567

根据上面的规则我们可以将其看为如图的一个堆:

从最后一个非叶子结点即结点3开始,我们比较结点3的值和他左右孩子的大小,如果结点3的值小于等于其左右孩子,那么不变,否则我们将左右孩子中较小的和结点3的值交换。

调整函数如下:

void FilterDown(int* nums, int start, int end)
{
	int i = start, j = i * 2 + 1;
	int tmp = nums[i];
	while (j <= end)
	{
		if (j < end && nums[j] > nums[j + 1]) j += 1;
		if (tmp <= nums[j]) break;
		nums[i]=nums[j];
		i = j;
		j = i * 2 + 1;
	}
	nums[i] = tmp;
}

然后找到结点3上一个结点,递归此过程,得到的就是最小堆,接下来只需交换堆根和堆末尾元素,并重复此过程,排序就完成.

三 代码实现

void FilterDown(int* nums, int start, int end)
{
	int i = start, j = i * 2 + 1;
	int tmp = nums[i];
	while (j <= end)
	{
		if (j < end && nums[j] > nums[j + 1]) j += 1;
		if (tmp <= nums[j]) break;
		nums[i]=nums[j];
		i = j;
		j = i * 2 + 1;
	}
	nums[i] = tmp;
}

void HeapSort(int* nums, int n)
{
	if (nullptr == nums || n < 2) return;
	int pos = (n - 2) / 2;
	while (pos >= 0)
	{
		FilterDown(nums, pos, n - 1);
		--pos;
	}
	pos = n - 1;
	while (pos > 1)
	{
		swap(nums[0], nums[pos]);
		--pos;
		FilterDown(nums, 0, pos);
	}
}
int main()
{
	int ar[] = { 53,17,78,9,45,65,87,23,};
	int len = sizeof(ar) / sizeof(ar[0]);
	HeapSort(ar, len);
	for (int i = 0; i < len; ++i)
	{
		cout << ar[i] << "  ";
	}
	cout << endl;
}

运行结果如下

拓展:c++实现优先级队列

我们都知道队列是一种先进先出的数据类型,但是优先级队列更像一个堆,它不满足先进先出地条件,优先级队列每次出队的元素是队列中优先级最高的那个元素,而不是队首的元素。这个优先级可以通过元素的大小等进行定义,比如数据越小优先级越高,那么先出的就是队列中最小的元素。

class MinHeap
{
private:
	int* data;
	int cursize;
	int maxsize;
public:
	static void FilterDown(int* nums, int start, int end)
	{
		int i = start, j = i * 2 + 1;
		int tmp = nums[i];
		while (j <= end)
		{
			if (j < end && nums[j] > nums[j + 1]) j += 1;
			if (tmp <= nums[j]) break;
			nums[i] = nums[j];
			i = j;
			j = i * 2 + 1;
		}
		nums[i] = tmp;
	}

	static void FilterUp(int* nums, int start)
	{
		int j = start, i = (j - 1) / 2;
		int tmp = nums[j];
		while (j > 0)
		{
			if (nums[i] <= tmp) break;
			nums[j] = nums[i];
			j = i;
			i = (i - 1) / 2;
		}
		nums[j] = tmp;
	}
public:
	MinHeap(int sz = 100)
	{
		cursize = 0;
		maxsize = sz;
		data =new int[maxsize];
	}
	~MinHeap()
	{
		delete[]data;
		data = nullptr;
		cursize = 0;
		maxsize = 0;
	}
	int getsize()const { return cursize; }
	bool IsEmpty()const { return getsize() == 0; }
	bool IsFull()const { return getsize() == maxsize;}
	void clear() { cursize = 0; }
	bool push(const int& val)
	{
		if (IsFull()) return false;
		data[cursize] = val;
		cursize += 1;
		FilterUp(data, cursize - 1);
		return true;
	}
	bool remove(int& val)
	{
		if (IsEmpty()) return false;
		val = data[0];
		data[0] = data[cursize - 1];
		cursize -= 1;
		FilterDown(data, 0, cursize - 1);
		return true;
	}
};

int main()
{
	MinHeap mh(100);
	mh.push(12);
	mh.push(34);
	mh.push(25);
	mh.push(8);
	mh.push(56);
	while (!mh.IsEmpty())
	{
		int x = 0;
		mh.remove(x);
		printf("%5d\n", x);
	}
	return 0;
}

结果如下:

 

感谢观看!

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值