队列的顺序实现
顺序队列的定义
typedef struct//顺序队列的定义
{
int data[Maxsize];//静态数组
int front, rear;//队头指针 队尾指针
}SqQueue;
顺序队列的初始化
队尾指针指向队尾元素的下一个位置
void InitQueue(SqQueue& Q)//初始化队列
{
Q.rear = Q.front = 0;//初始时队列的队头队尾指向0
}
判断顺序队列是否为空
队列为空的条件:Q.rear==Q.front;
bool QueueEmpty(SqQueue Q)//判断队列是否为空
{
if (Q.rear = Q.front)return 1;
else return 0;
}
判断顺序队列是否为满(循环队列)
判满条件:(Q.rear + 1) % Maxsize == Q.front
为了避免判满条件与判空条件一致所以牺牲一个单位的存储空间用以区别
bool QueueFull(SqQueue Q)//判断队列是否为满(循环队列)
{
if ((Q.rear + 1) % Maxsize == Q.front)return 1;//牺牲一个空间避免满的条件与空的条件一致
else return 0;
}
顺序队列的入队
元素只能从队尾入队 为了节省空间队尾指针会适用取模运算利用起数组前面已经出队了的没有元素的空间(循环队列)
bool EnQueue(SqQueue& Q, int x)//入队(循环队列)
{
if ((Q.rear + 1) % Maxsize == Q.front)return 0;//队列满返回0
Q.data[Q.rear] = x;//新元素插入队尾
Q.rear = (Q.rear + 1) % Maxsize;//队尾指针取模加一(循环队列)
return 1;
}
顺序队列的出队
bool DeQueue(SqQueue& Q, int& x)//出队 并用x接收出队元素(循环队列)
{
if (Q.rear == Q.front)return 0;//队空返回0
x = Q.data[Q.front];
Q.front = (Q.front + 1) % Maxsize;//循环队列 取模
return 1;
}
顺序队列的获取当前对头元素
bool GetHead(SqQueue Q, int& x)//获得对头元素的值
{
if (Q.rear == Q.front)return 0;//队空返回0
x = Q.data[Q.front];
return 1;
}
顺序队列的判断队满队空方案二(不浪费空间)
结构体中定义一个size变量记录当前队列的长度,size初始为0,size=0时队列空,size=Maxsize时队列为满
顺序队列的判断队满队空方案三(不浪费空间)
结构体中定义一个tag变量 tag=1时代表上次执行了一次入队操作 tag=0时代表上次执行了一次出队操作;只有出队操作才会使队列为空,只有入队操作才会使队列为满。
跟具tag的值来判断Q.rear=Q.front时队满开始队空
顺序队列——队尾指针指向队尾元素情况
队列初始化
void InitQueue(SqQueue& Q)//初始化队列
{
Q.front = 0;
Q.rear = Maxsize-1;
}
入队操作
Q.rear=(Q.rear+1)%Maxsize;
Q.data[Q.rear]=x;
判断空
if((Q.rear+1)%Maxsize==Q.front)
判断满
方案一
牺牲一个存储单元
if((Q.rear+2)%Maxsize==Q.front)
方案二
增加一个辅助变量
队列的链式实现
链式队列的定义
typedef struct Linknode{//链式队列结点
int data;
Linknode* next;
}Linknode;
typedef struct {//链式队列
Linknode* front, * rear;//队列的对头和队尾指针
}LinkQueue;
带头结点的初始化
void InitQueue(LinkQueue& Q)//带头结点的初始化
{
Q.front = Q.rear = new Linknode;//初始时front和rear都指向头结点
Q.front->next = NULL;
}
带头节点的判空
判空条件:Q.front=Q.rear或者Q.front->next=NULL
bool IsEmpty(LinkQueue Q)//带头结点判空
{
if (Q.front == Q.rear)return 1;
else return 0;
}
带头结点的入队
void EnQueue(LinkQueue& Q, int x)//入队
{
Linknode* s = new Linknode;
s->data = x;
s->next = NULL;
Q.rear->next = s;//新节点插入到rear之后
Q.rear = s;//修改尾表指针
}
带头结点出队
bool DeQueue(LinkQueue& Q, int &x)//带头节点出队 x变量接收出队的值
{
if (Q.front == Q.rear)return 0;//队列为空返回0
Linknode* p = Q.front->next;
x = p->data;//x接收出队的值
Q.front->next = p->next;//链表中删除p指向的结点
if (Q.rear == p)//此次是最后一个结点出队
Q.front == Q.rear;//修改rear指针
delete p;
return 1;
}
不带头结点入队
void NenQueue(LinkQueue& Q, int x)//不带头结点入队
{
Linknode* s = new Linknode;
s->data = x;
s->next = NULL;
if (Q.front == NULL)//如果为空元素 再空队列中插入第一个元素
{
Q.front = s;//修改头尾指针
Q.rear = s;
}
else//不为空新节点插入到rear指针之后再修改rear指针
{
Q.rear->next = s;
Q.rear = s;
}
}
双端队列
只允许从两端插入、两端删除的线性表
输入受限的双端队列:只允许从一端插入、两端删除的线性表
输出受限的双端队列:只允许从两端插入、一端删除的线性表
队列的应用
树的层次遍历
图的广度优先遍历
队列在操作系统中的应用
-
多个进程争抢着使用系统资源时,FCFS(first come first service)是一种常用策略
-
打印数据缓冲区