C++ 数据结构算法 学习笔记(11) - 队列及企业级应用 (续4)
优先队列
英雄联盟游戏里面防御塔都有一个自动攻击功能,小兵排着队进入防御塔的攻击范围,防御塔先 攻击靠得最近的小兵,这时候大炮车的优先级更高(因为系统判定大炮车对于防御塔的威胁更大), 所以防御塔会优先攻击大炮车。而当大炮车阵亡,剩下的全部都是普通小兵,这时候离得近的优 先级越高,防御塔优先攻击距离更近的小兵。
优先队列: 它的入队顺序没有变化,但是出队的顺序是根据优先级的高低来决定的。优先级高的 优先出队
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 = 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;
}
int EnterQueue(LinkQueue* LQ, DataType data, int priority) {
if (!LQ) return 0;
if (IsFull(LQ)) {
cout << "Not able to insert data " << data << ", because the queus is already FULL!" << endl;
return 0;
}
QNode* qNode = new QNode;
qNode->data = data;
qNode->priority = priority;
qNode->next = NULL;
if (IsEmpty(LQ)) {
LQ->front = LQ->rear = qNode;
}
else {
LQ->rear->next = qNode;
LQ->rear = qNode;
}
LQ->length++;
return 1;
}
int DeleteQueue(LinkQueue* LQ, DataType* data) {
QNode** prev = NULL, * prev_node = NULL;
QNode* last = NULL, * tmp = NULL;
if (!LQ || IsEmpty(LQ)) {
cout << "The queue is NULL!" << endl;
return 0;
}
if (!data) return 0;
prev = &(LQ->front);
printf("The first node priority is: %d\n", (*prev)->priority);
last = LQ->front;
tmp = last->next;
while (tmp) {
if (tmp->priority > last->priority) {
printf("Get a higher priority [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--;
if (LQ->length == 0) {
LQ->rear = NULL;
}
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 << "The queue is NULL!";
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 << "The queue is NULL!" << 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 = 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("The element inside the list have (total %d ):", getLength(LQ));
PrintQueue(LQ);
cout << endl;
for (int i = 0; i < 5; i++) {
if (DeleteQueue(LQ, &data)) {
cout << "The come out element is :" << data << endl;
}
else {
cout << "Fail to come out!" << endl;
}
}
//
printf("After the five time remove element ,The queue element now left [%d]:\n", getLength(LQ));
PrintQueue(LQ);
cout << endl;
ClearQueue(LQ);
cout << "Clear the queue!\n";
PrintQueue(LQ);
delete LQ;
system("pause");
return 0;
}
这里面代码杂的是在 DeleteQueue
里面, 里面涉及到了2级指针.
int DeleteQueue(LinkQueue* LQ, DataType* data) {
QNode** prev = NULL, * prev_node = NULL;
QNode* last = NULL, * tmp = NULL;
if (!LQ || IsEmpty(LQ)) {
cout << "The queue is NULL!" << endl;
return 0;
}
if (!data) return 0;
prev = &(LQ->front);
printf("The first node priority is: %d\n", (*prev)->priority);
last = LQ->front;
tmp = last->next;
while (tmp) {
if (tmp->priority > last->priority) {
printf("Get a higher priority [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--;
if (LQ->length == 0) {
LQ->rear = NULL;
}
if (prev_node && prev_node->next == NULL) {
LQ->rear = prev_node;
}
return 1;
}
注:难点
prev = &(last->next);
可否改成prev = &tmp;
?- 答:不可以,因为不是一样的东西.
tmp
只是一个临时的节点指针,让prev = &tmp
没用. 但是让prev = &(last->next)
可以让 当前last
节点的next
的地址赋值为prev.
这样做的目的是后续可以直接让这个值改成下一个节点的next
.这样的话后续删除下一个节点后这个next
可以指向删除了的节点的next
从而导致整个队列完整.
- 答:不可以,因为不是一样的东西.
*prev = (*prev)->next;
其实有什么作用?prev
好像代码后面都不会用到了?为什么还要赋值给下一个节点的next
- 答: 这个非常重要. 这个的目的是让
prev
(原本这个是一个节点的next
的地址)变成下一个节点的next
地址.原因是下一个节点会被删除掉,所以需要修改这个prev
值.不然的话整个队列都不会完整!
- 答: 这个非常重要. 这个的目的是让