笔记:堆和优先队列

本文介绍了完全二叉树的概念及其在堆数据结构中的应用,包括大顶堆和小顶堆的性质,以及堆的插入和弹出操作,同时给出了C++代码实现。
摘要由CSDN通过智能技术生成

好久没有写博客了┭┮﹏┭┮这几天感冒了,不过今天更新啦!

一、完全二叉树

要学习堆,首先我们得回顾一下完全二叉树,以下是一棵完全二叉树。

完全二叉树是一种特殊的二叉树结构,它的定义如下:

  • 在完全二叉树中,除了最后一层的叶节点可能不满外,其他各层的节点都必须填满。
  • 叶节点尽量都集中在树的左侧。
  • 如果某个节点的右子树为空,则其左子树也必须为空。

完全二叉树中,从上到下、从左到右依次编号,可以得到节点的编号序列。对于任意编号为n的节点:

  • 如果n=1,它是根节点;
  • 如果n>1,其父节点编号为n/2(取整);
  • 如果2n <= 总节点数,其左子节点编号为2n;
  • 如果2n+1 <= 总节点数,其右子节点编号为2n+1。

完全二叉树的特点使得它可以用数组来表示,数组的索引对应了节点的编号,数组中的值对应了节点的值。这种表示方法使得完全二叉树的操作更加高效。

这么多性质是不是非常头疼呢?

但是其实可以综合为图中的两个性质!

不过我们不一定要以1为起始节点,我们当然可以使用0作为根节点编号,此时左子树编号为2*i+1,右子树编号为2*i+2。但是我们会发现,这样如果使用编号去遍历二叉树子树的运算次数是4!但是以1作为根节点编号的二叉树子树的遍历运算次数为3!

所以我们说:以1为根节点编号的完全二叉树更优!

二、堆 

现在,我们了解了完全二叉树的基础知识,可以进一步学习堆的知识了!

这边介绍两种最简单的堆:大顶堆和小顶堆。

①大顶堆

它满足以下性质:

  1. 堆中的任意父节点的值都大于或等于其子节点的值。
  2. 堆中的最大元素存储在根节点,也就是堆顶。

 

②小顶堆

 它满足以下性质:

  1. 堆中的任意父节点的值都小于或等于其子节点的值。
  2. 堆中的最小元素存储在根节点,也就是堆顶。

三、堆的插入与弹出 

1、堆的插入

堆的尾部插入调整

我们想在这个大顶堆中插入节点 13 ,如何操作呢?

首先在完全二叉树的末尾加入节点 13 ,如图所示:

我们依次去寻找它的父节点,如果比父节点大则交换,否则不变。

过程如下:

 

 

 

 2、堆的弹出

 堆的头部弹出调整

先弹出,将最后一个节点补到头部,再进行调整。

调整过程:找到父 左 右 三个节点最大的节点,如果不是父节点,则将父节点与之交换,否则不变。

 

 

四、优先队列 

优先队列是一种特殊的队列,其中的元素具有优先级。元素的优先级可以是任意类型的,可以是整数、浮点数、字符串等。在优先队列中,元素按照优先级的顺序被访问和删除,而不是按照插入的顺序。

优先队列可以用于解决一些问题,如任务调度、最短路径问题等。在任务调度中,每个任务都有一个优先级,优先级高的任务会被优先执行;在最短路径问题中,每个节点都有一个权重,优先队列可以根据权重的大小来选择下一个要访问的节点。

 

 

 代码实现:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROOT 1
#define FATHER(i) ((i)/2)
#define LEFT(i) ((i)*2)
#define RIGHT(i) ((i)*2+1)
#define cmp >
#define swap(a,b){ \
	__typeof(a) __c = (a); \
	(a) = (b); \
	(b) = __c; \
}
using namespace std;
typedef struct PriorityQueue{
	int *__data,*data;//连续的一段数组空间
	int size;//存储空间的大小
	int n;//当前存储元素数
}PriorityQueue;

PriorityQueue *initPQ(int size){
	PriorityQueue *p = new PriorityQueue;
	p->__data = new int[size];
	p->data = p->__data - 1;
	p->size = size;
	p->n = 0;
	return p;
}

int empty(PriorityQueue *p){
	return p->n == 0;
}
int full(PriorityQueue *p){
	return p->n == p->size;
}
int top(PriorityQueue *p){
	return p->data[ROOT];
}

void up_update(int *data,int i){

	if(i == ROOT) return;
	if(data[i] cmp data[FATHER(i)]){
		swap(data[i],data[FATHER(i)]);
		up_update(data,FATHER(i));
	}
}

void down_update(int *data,int i,int n){
	int ind;
	while(LEFT(i) <= n){
		ind = i;
		int l = LEFT(i);
		int r = RIGHT(i);
		if (data[l] cmp data[ind]) ind = l;
		if (r <= n && data[r] cmp data[ind]) ind = r;
		if (ind == i) break;
		swap(data[i],data[ind]);
		i = ind;
	}
	return;
}
int push(PriorityQueue *p, int x){
	if(full(p)) return 0;
	p->n += 1;
	p->data[p->n] = x;
	up_update(p->data,p->n);//进行向上调整
	return 1;
}

int pop(PriorityQueue *p){
	if(empty(p)) return 0;
	p->data[ROOT] = p->data[p->n];
	p->n -= 1;
	down_update(p->data,ROOT,p->n);//进行
	return 1;
}

void clearPQ(PriorityQueue *p){
	if(p == NULL) return;
	delete(p->__data);
	delete(p);
	return;
}
void output(PriorityQueue *p){
	printf("PQ(%d) :",p->n);
	for(int i = 1;i <= p->n;i++){
		printf("%d ",p->data[i]);
	}
	printf("\n");
	return;
}
int main(){
	int op,x;
	#define MAX_OP 100
	PriorityQueue *p = initPQ(MAX_OP);
	while (~scanf("%d",&op)){
		if(op == 1){
			scanf("%d",&x);
			printf("insert %d to priority_queue: \n",x);
			push(p,x);
			output(p);
		}else {
			printf("top : %d\n",top(p));
			pop(p);
			output(p);
		}
	}
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值