C/C++_数据结构和算法_优先级队列

**

优先级队列

**

英雄联盟游戏里面防御塔都有一个自动攻击功能,小兵排着队进入防御塔的攻击范围,防御塔先 攻击靠得最近的小兵,这时候大炮车的优先级更高(因为系统判定大炮车对于防御塔的威胁更大), 所以防御塔会优先攻击大炮车。而当大炮车阵亡,剩下的全部都是普通小兵,这时候离得近的优 先级越高,防御塔优先攻击距离更近的小兵。
在这里插入图片描述
优先队列: 它的入队顺序没有变化,但是出队的顺序是根据优先级的高低来决定的。优先级高的 优先出队。
在这里插入图片描述

typedef int DataType; //队列中元素类型 

typedef struct _QNode //结点结构 
{ 
	int priority; //每个节点的优先级,9 最高优先级,0 最低优先级,优先级相同, 取第一个节点 
	DataType data; 
	struct _QNode *next; 
}QNode;

typedef QNode* QueuePtr; 

typedef struct Queue 
{
	int length; //队列的长度 
	QueuePtr front; //队头指针 
	QueuePtr rear; //队尾指针 

}LinkQueue;

空的任务队列 & 插入元素

在这里插入图片描述
删除一个节点
在这里插入图片描述

参考:

#include <stdio.h>
#include <assert.h>
#include <Windows.h>
#include <iostream>
#include <iomanip>

using namespace std;

#define MAXSIZE 5		//队列的最大容量

typedef int DataType;	//任务队列中元素的类型

typedef struct _QNode	//节点结构
{
	int priority;		//优先级
	DataType data;		
	struct _QNode* next;
}QNode;

typedef QNode* QueuePtr;

typedef struct Queue
{
	int length;			//队列的长度
	QueuePtr front;
	QueuePtr rear;
}LinkQueue;

//队列初始化, 将队列初始化为空队列
void InitQueue(LinkQueue* LQ)
{
	if (!LQ) return;

	LQ->length = 0;
	LQ->front = NULL;
	LQ->rear = NULL;
}

//判断队列为空
int IsEmpty(LinkQueue* LQ)
{
	if (!LQ) return 0;

	if (LQ->front == NULL)
	{
		return 1;
	}

	return 0;
}

//判断队列是否为满
int IsFull(LinkQueue* LQ)
{
	if (!LQ) return 0;

	if (LQ->length == MAXSIZE)
	{
		return 1;
	}

	return 0;
}


//入队, 将元素 data 插入到队列LQ中
int EnterQueue(LinkQueue* LQ, DataType data, int priority)
{
	if (!LQ) return 0;

	if (IsFull(LQ))
	{
		cout << "无法插入元素 " << data << ", 队列已满!" << endl;
		return 0;
	}

	QNode* qNode = new QNode;
	
	qNode->data = data;
	qNode->priority = priority;
	qNode->next = NULL;

	if (IsEmpty(LQ)) //空队列
	{
		LQ->front = qNode;
		LQ->rear = qNode;
	}
	else
	{
		LQ->rear->next = qNode;
		LQ->rear = qNode;
	}
	LQ->length++;

	return 1;
}

//出队, 遍历队列, 找到队列中优先级最高的元素data出队
int DeleteQueue(LinkQueue* LQ, DataType* data)
{
	QNode** prev = NULL;
	QNode* prev_node = NULL; //保存当前已选举的最高优先级节点上一个节点的指针地址
	QNode* last = NULL;
	QNode* tmp = NULL;

	if (!LQ || IsEmpty(LQ))
	{
		cout << "队列为空!" << endl;
		return 0;
	}

	if (!data) return 0;
	//prev 指向队头 front 指针的地址
	prev = &(LQ->front);
	printf("第一个节点的优先级: %d\n", (*prev)->priority);
	last = LQ->front;
	tmp = last->next;
	while (tmp)
	{
		if (tmp->priority > (*prev)->priority)
		{
			printf("抓到个更大的优先级的节点[priority: %d]\n", tmp->priority);
			prev = &(last->next);
			prev_node = last;

		}
		last = tmp;
		tmp = tmp->next;
	}

	*data = (*prev)->data;
	tmp = *prev;
	*prev = (*prev)->next;
	delete tmp;

	LQ->length--;


	//接下来存在2种情况需要分别对待
	//1. 删除的首节点, 而且的队列长度为零
	if (LQ->length == 0)
	{
		LQ->rear = NULL; 
		LQ->front = NULL;
	}

	//2. 删除尾部节点
	if (prev_node && prev_node->next == NULL)
	{
		LQ->rear = prev_node;
	}

	return 1;
}

//打印队列中的各个元素
void PrintQueue(LinkQueue* LQ)
{
	QueuePtr tmp;

	if (!LQ) return;

	if (LQ->front == NULL)
	{
		cout << "队列为空! " << endl;
		return;
	}

	tmp = LQ->front;
	while (tmp)
	{
		cout << setw(4) << tmp->data << "[" << tmp->priority << "]";
		tmp = tmp->next;
	}
	cout << endl;
}

//获取队首的元素, 不出队
int GetHead(LinkQueue* LQ, DataType* data)
{
	if (!LQ || IsEmpty(LQ))
	{
		cout << "队列为空" << endl;
		return 0;
	}

	if (!data) return 0;

	*data = LQ->front->data;
	return 1;
}

//清空队列
void ClearQueue(LinkQueue* LQ)
{
	if (!LQ) return;

	while (LQ->front)
	{
		QueuePtr tmp = LQ->front->next;
		delete LQ->front;
		LQ->front = tmp;
	}

	LQ->front = NULL;
	LQ->rear = NULL;
	LQ->length = 0;
}


//获取队列中的元素的个数
int getLength(LinkQueue* LQ)
{
	if (!LQ) return 0;

	return LQ->length;
}

int main()
{
	LinkQueue* LQ = new LinkQueue;
	DataType data = -1;

	//初始化队列
	InitQueue(LQ);

	//入队
	for (int i = 0; i < 5; i++)
	{
		EnterQueue(LQ, i + 10, i);
	}

	//打印队列中的元素
	printf("队列中的元素(总共 %d 个): ", getLength(LQ));
	PrintQueue(LQ);
	cout << endl;

	//出队
	for (int i = 0; i < 5; i++)
	{
		if (DeleteQueue(LQ, &data))
		{
			cout << "出队的元素是: " << data << endl;
		}
		else
		{
			cout << "出队失败! " << endl;
		}
	}

	//打印队列中的元素
	printf("出队 5 个元素后, 队列中剩下的元素[%d]: \n", getLength(LQ));
	PrintQueue(LQ);
	cout << endl;

	ClearQueue(LQ);
	cout << "清空队列!\n" << endl;
	PrintQueue(LQ);

	//清空资源
	delete LQ;

	system("pause");
	return 0;
}

编译环境: vs2019
运行结果:
在这里插入图片描述

结语:

学到的知识要, 多复习, 多总结, 多敲. 需要时间的积累, 才能引起质的改变. 自己写不出来的永远是别人的.

如果说这个知识点分 10 层, 我觉得我现在才 3 层(可能还不到).

分享一下我的技巧: 代数法把具体的数字带进去, 看看能能能找到规律.
还有就是画图, 也很重要. 用笔画出来, 把数代进去, 方法虽然笨, 但真的很实用, 好记忆不如烂笔头!!!

我是小白, 如果存在问题, 欢迎大神给予评判指正.
错了不可怕, 可怕的是找不出bug

希望给个赞: 反正你又不亏, 顺便而已

青春励志: 真正的强者, 不是流泪的人, 而是含泪奔跑的人.
名词新意: [现实] 一种与想象截然相反的生活.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weifc-wei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值