提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
数据结构之队列
课程链接:【【强烈推荐】深入浅出数据结构 - 顶尖程序员图文讲解 - UP主翻译校对 (已完结)】 https://www.bilibili.com/video/BV1Fv4y1f7T1/?p=17&share_source=copy_web&vd_source=a380547882bee6e5ecb87e70ac629227
————————————————
一、队列
队列先进先出,栈先进后出。
栈的插入和弹出都必须从一端进行,称为栈顶。
列表元素的插入必须从队尾进行,元素删除必须从另外一段,即队头进行。
- 应用场景:多个程序请求同一资源,该资源一次只能服务一个请求
二、实验代码
1.使用数组实现队列
循环数组的概念
使用数组实现列表,会首先一定大小的数组内存,但在执行一系列的入队列出队列操作后,尾部来到了数组的一端,不能再执行插入操作,出现内存浪费。
考虑采用循环数组,循环数组的索引需要依靠取模求余数运算。
- 代码实现
#include<iostream>
using namespace std;
#define N 5
int A[N];
int front = -1;//初始化队头
int rear = -1;//初始化队尾
bool IsEmpty();
bool IsFull();
int Front();//获取队头元素
void InQueue(int x);//插入队列元素
void DeQueue();//删除队列元素
void Print_Queue();
int main()
{
InQueue(1);
InQueue(2);
InQueue(3);
InQueue(4);
InQueue(5);
InQueue(6);//满了
Print_Queue();//12345
cout << Front() << endl;//1
DeQueue();
DeQueue();
Print_Queue();//345
DeQueue();
DeQueue();
DeQueue();
DeQueue();//空队列去删,显示队列为空
cout << Front() << endl;//显示队列为空,返回NULL
}
bool IsEmpty()
{
if (front == -1 && rear == -1)
{
return true;
}
else
{
return false;
}
}
bool IsFull()
{
if ((rear + 1) % N == front)
{
return true;
}
else
{
return false;
}
}
int Front()
{
if (IsEmpty())
{
cout << "列表为空,无法读取!!!" << endl;
return 0;
}
return A[front];
}
void InQueue(int x)
{
if (IsFull())
{
cout<<"列表已满,无法加入!!!" << endl;
return;
}
else if (IsEmpty())
{
front = 0;
rear = 0;
}
else
{
rear = (rear + 1) % N;
}
A[rear] = x;
}
void DeQueue()
{
if (IsEmpty())
{
cout<<"列表为空,无法删除!!!" << endl;
return;
}
else if (front == rear)//删除列表元素,此时只剩最后一个,头尾指向的一样
{
front = -1;
rear = -1;
}
else
{
front = (front + 1) % N;
}
}
void Print_Queue()
{
for (int i = front; i != rear; i = (i + 1) % N)
{
cout << A[i] << ' ';
}
cout << A[rear];
cout << endl;
}
2.使用链表实现队列
- 需要定义一个front始终指向队头和rear始终指向队尾,删除从队头删除,插入从队尾插入,时间复杂度都是O(1)。如果只有队头或者队尾,在完成删除或者插入的操作时,有一个需要遍历整个队列,那么时间复杂度将是O(n)
- 相比数组实现,数组实现大小固定,需要扩展时需复制整个数组,或者有未使用的内存造成浪费;而链表实现,除了需要额外的内存来存放下一个节点的地址,但内存利用率更高
代码如下(示例):
#include<iostream>
using namespace std;
struct Node {
int data;
struct Node* next;
};
//初始化 全局变量
struct Node* front = NULL;
struct Node* rear = NULL;
void enqueue(int x);
void dequeue();
bool IsEmpty();
int Front();
void print();
int main()
{
enqueue(1);
enqueue(2);
enqueue(3);
print();//1 2 3
cout << "队头元素为:" << Front() << endl;
dequeue();
dequeue();
print();//3
dequeue();
print();//
dequeue();//不能删除
}
bool IsEmpty()
{
if (front == NULL && rear == NULL)
{
return true;
}
else
{
return false;
}
}
void enqueue(int x)
{
//创建一个temp指针(在栈区),指向新创建的节点(节点创建在堆区)
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = x;
temp->next = NULL;
if (IsEmpty())//队列为空
{
front = rear = temp;
return;
}
else
{
rear->next = temp;
rear = temp;
}
}
void dequeue()
{
//创建一个temp指针(在栈区),指向front指向的节点(节点存储在堆区)
struct Node* temp = front;
if (IsEmpty())
{
cout << "已经空了 不能删除" << endl;
return;
}
else if (front == rear)
{
front = rear = NULL;
}
else
{
front = front->next;
}
free(temp);//释放被删除的节点
}
int Front()
{
if (IsEmpty())
{
cout << "空队列!!" << endl;
return NULL;
}
else
{
return front->data;
}
}
void print() {
cout << "队列为:";
struct Node* temp = front;
while (temp != NULL) {
cout << temp->data << ' ';
temp = temp->next;
}
cout << endl;
}