优先队列及二叉堆

本文借优先队列,重点讲解二叉堆

优先队列:

能完成以下操作的数据结构叫做优先队列:
1.插入一个数值
2.取出最小的数值(获得数值,并且删除)
在这里插入图片描述

 

二叉堆:

能够使用二叉树有效地解决上述问题(优先队列),是一种叫做“堆”的数据结构,即二叉堆。

所以二叉堆是二叉树优先队列结合的数据结构。

二叉堆示意图:
在这里插入图片描述
像这样的二叉堆特点:
1.儿子结点的值一定不小于父结点的值
2.结点按从上到下、从左到右的顺序紧凑排列
我们称这样的二叉堆为最小堆

当然我们还可以有这样的二叉堆:
在这里插入图片描述
像这样的二叉堆特点:
1.父结点的值一定不小于儿子结点的值
2.结点按从上到下、从左到右的顺序紧凑排列
我们称这样的二叉堆为最大堆

 

二叉堆插入和取值操作(最大/小值):

以第一种二叉堆为例

插入操作:
在向堆中插入数值时,首先在堆的末尾插入该数值,然后向上不断提升,直到没有大小颠倒为止。
在这里插入图片描述
插入完成之后:
在这里插入图片描述

删除操作:
删除堆中的最小值,首先把堆的最后一个结点的数值复制到根结点上,并且删除最后一个结点。然后不断向下交换直到没有大小颠倒为止。向下交换过程中,如果有两个儿子结点,那么和较小的儿子结点交换。
在这里插入图片描述
删除操作结果:
在这里插入图片描述
 

用C实现上述二叉堆操作:

#include <stdio.h>
#include <stdlib.h>

int heap[100],sz;//sz为数值个数

//把数值放入二叉堆中 
void push(int x){
	int i=sz++;
	
	while(i>0){
		//父亲结点的编号(无论是左儿子还是右儿子都用该公式) 
		int p=(i-1)/2;
		
		//如果已经没有大小颠倒就退出
		if(heap[p]<=x) break;
		
		//把父结点的数值放下来,把自己的数值提上去
		heap[i]=heap[p];
		i=p; 
	}
	
	heap[i]=x;
}

//将最小值取出二叉堆 
int pop(){
	//最小值
	int ret=heap[0];
	
	//该数值要提到根
	int x=heap[--sz];
	
	//从根开始向下交换
	int i=0;
	while(i*2+1<sz){
		//比较儿子的值
		int a=i*2+1,b=i*2+2;
		if(b<sz&&heap[b]<heap[a])a=b;//操作右儿子
		
		//没有大小颠倒则退出
		if(heap[a]>=x)break;
		
		//把儿子的数值提上来
		heap[i]=heap[a];
		i=a;//根结点下移 
	} 
	heap[i]=x;
	
	return ret;
}

int main(int argc, char *argv[]) {
	int i;
	printf("请输入二叉堆中的有几个数:\n");
	scanf("%d",&sz);
	
	printf("请输入这几个数值:\n");
	for(i=0;i<sz;i++){
		scanf("%d",&heap[i]);
	}
	
	int x;
	printf("请输入要放入二叉堆中的值:\n");
	scanf("%d",&x);
	push(x);
	
	printf("这时数组为:\n");
	for(i=0;i<sz;i++){
		if(i>0) printf(" ");
		printf("%d",heap[i]);
	}
	
	printf("\n------------\n");
	
	printf("将最小值取出:\n");
	printf("%d\n",pop());
	printf("这时数组为:\n");
	for(i=0;i<sz;i++){
		if(i>0) printf(" ");
		printf("%d",heap[i]);
	}
	return 0;
}

 
实际上,大部分情况下不需要我们自己实现二叉堆。在许多编程语言中,都包含了优先队列的高效实现。例如C++中,STL里的priority_queue就是其中之一。
而其实现的是我们所讲的第二种,即取出数值时得到的是最大值。

C++优先队列:

#include <iostream>
#include <queue>
#include <cstdio>

using namespace std;

int main(int argc, char** argv) {
	//声明
	priority_queue<int> pque;
	
	//插入元素
	pque.push(3);
	pque.push(5);
	pque.push(1);
	
	//不断循环直到为空
	while(!pque.empty()){
		//获取最大值 
		printf("%d ",pque.top());
		//删除最大值 
		pque.pop(); 
	} 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值