数据结构之顺序队列
数据结构之队列
什么是队列
- 队列是和栈一样
操作受限
的线性表,栈是只允许在线性表的一端进行入栈和出栈操作,而队列是会允许在线性表的一端进行入队,在另外一端进行出队操作
队列的基本操作
bool initQueue(Queue & Q); // 初始化队列
void destroyQueue(Queue Q); // 如果是顺序队列则不需要销毁
bool push(Queue & Q, ElemType x); // 入队
bool pop(Queue & Q, ElemType & x); // 出队
// 获取队头元素的值
void getTop(Queue Q, ELemType & x);
bool queueEmpty(Queue Q); // 判断队列是否为空
顺序队列
- 用静态数组实现的队列(使用顺序存储结构实现的队列)
缺点:空间固定
顺序队列的代码实现
#include<stdio.h>
#define Elemtype int
#define MaxSize 10
typedef struct SQueue{
Elemtype data[MaxSize];
size_t front,rear; // 队头和队尾指针(存储数组下标)
}SQueue;
bool initQueue(SQueue & Q)
{
Q.front = 0;
Q.rear = 0;
}
// 入队
bool push(Queue & Q, ElemType x)
{
// 如果队列满了则返回false
if((Q.rear + 1) % MaxSize == Q.front)
return false;
Q.data[Q.rear] = x;
Q.rear = (Q.rear+1) % MaxSize;
}
// 出队
bool pop(Queue & Q, ElemType & x)
{
// 如果队列为空,则返回false
if(Q.front == Q.rear)
return false
x = Q.data[Q.front];
Q.front = (Q.front + 1) % MaxSize;
}
// 获取队头元素的值
void getTop(Queue Q, ELemType & x){
// 如果队列为空,则返回false
if(Q.front == Q.rear)
return false
x = Q.data[Q.front];
}
// 判断队列是否为空
bool SqueueEmpty(SQueue Q);{
if(Q.front == Q.rear)
return true;
return false;
}
代码缺陷
上述代码实现的队列,会浪费一个存储空间,如何避免浪费一个存储空间呢?
- 使用一个length变量,存储队列的长度
typedef struct SQueue{
Elemtype data[MaxSize];
size_t front,rear; // 队头和队尾指针(存储数组下标)
Size_t length;
}SQueue;
bool initQueue(SQueue & Q)
{
Q.front = 0;
Q.rear = 0;
Q.length = 0; // 计数器
}
// 入队
bool push(Queue & Q, ElemType x)
{
// 如果队列满了则返回false
if(Q.front == Q.rear && Q.length == MaxSize)
return false;
Q.data[Q.rear] = x;
Q.rear = (Q.rear+1) % MaxSize;
Q.length++;
}
// 出队
bool pop(Queue & Q, ElemType & x)
{
// 如果队列为空,则返回false
if(Q.front == Q.rear && Q.length == 0)
return false
x = Q.data[Q.front];
Q.front = (Q.front + 1) % MaxSize;
Q.rear--;
}
- 使用一个flag变量,出队时将flag 置为0 , 入队将flag置为1
typedef struct SQueue{
Elemtype data[MaxSize];
size_t front,rear; // 队头和队尾指针(存储数组下标)
bool flag;
}SQueue;
bool initQueue(SQueue & Q)
{
Q.front = 0;
Q.rear = 0;
}
// 入队
bool push(Queue & Q, ElemType x)
{
// 如果队列满了则返回false
if(Q.front == Q.rear && Q.flag = 1)
return false;
Q.data[Q.rear] = x;
Q.rear = (Q.rear+1) % MaxSize;
Q.flag = 1;
}
// 出队
bool pop(Queue & Q, ElemType & x)
{
// 如果队列为空,则返回false
if(Q.front == Q.rear && Q.flag == 0)
return false
x = Q.data[Q.front];
Q.front = (Q.front + 1) % MaxSize;
Q.rear--;
Q.flat = 0;
}
链式队列
- 用链表实现的队列(存储空间不固定,根据内存来确定)
#include<stdio.h>
#include<stdlib.h>
#define ElemType int
typedef struct LinkNode { // 链式队列结点
ElemType data;
struct LinkNode* next;
}LinkNode;
typedef struct {
LinkNode* front, * rear; // 队列的队头和队尾指针
}LinkQueue;
// 初始化链式队列
bool initLinkQueue(LinkQueue& LQ)
{
LinkNode* n = (LinkNode*)malloc(sizeof(LinkNode));
if (n == NULL)
return false;
n->next = NULL;
LQ.front = n;
LQ.rear = n;
return true;
}
// 销毁链式队列
void destoryQueue(LinkQueue& LQ)
{
LinkNode* cur = LQ.front->next;
LinkNode* next;
while (cur != NULL)
{
next = cur->next;
free(cur);
cur = next;
}
free(LQ.front); // 释放头结点
LQ.front = NULL;
LQ.rear = NULL;
}
// 判断链式队列为空
bool isEmpty(LinkQueue LQ)
{
if (LQ.front == LQ.rear)
return true;
else
return false;
}
// 入队
bool push(LinkQueue& LQ, ElemType x)
{
LinkNode* n = (LinkNode*)malloc(sizeof(LinkNode));
if (n == NULL)
return false;
n->data = x;
n->next = NULL;
LQ.rear->next = n;
LQ.rear = n; // 修改队尾指针
return true;
}
// 出队
bool pop(LinkQueue& LQ, ElemType& x)
{
if (isEmpty(LQ)) // 判断链式队列是否为空
return false;
LinkNode* head = LQ.front;
LinkNode* cur = head->next; // 当前要出的结点
x = cur->data;
head->next = cur->next;
if (LQ.rear == cur) // 此次出队的是最后一个结点
LQ.rear = LQ.front;
free(cur); // 释放结点
return true;
}
// 获取队头结点存放的数据
bool getTop(LinkQueue& LQ, ElemType& x)
{
if (isEmpty(LQ)) // 判断链式队列是否为空
return false;
LinkNode* head = LQ.front;
LinkNode* cur = head->next; // 队头结点
x = cur->data;
return true;
}
// 打印整个队列
void printQueue(LinkQueue LQ)
{
LinkNode* cur = LQ.front->next; // 作为遍历整个队列的结点
if(!isEmpty(LQ))
{
while (cur != NULL)
{
printf("%d <- ", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
}
// 测试函数
void test_LinkQueue(){
LinkQueue LQ;
initLinkQueue(LQ);
push(LQ, 1);
push(LQ, 2);
push(LQ, 3);
push(LQ, 4);
printQueue(LQ);
ElemType x = 0;
pop(LQ, x);
pop(LQ, x);
printQueue(LQ);
}
int main()
{
test_LinkQueue();
return 0;
}
队列的变种(双端队列)
双端队列:受限制的线性表,可以在线性表的两端进行插入和删除操作
- 双端队列只允许在队列的一端进行插入和删除操作就等价于栈
- 输入受限的双端队列: 只允许一端进行插入,两端允许删除的线性表
- 输出受限的双端队列: 只允许一段进行删除,两段允许插入的线性表
练习题:判断输出序列合法性
若数据元素输入序列为1,2,3,4,5 则哪些输出序列是合法的,哪些是非法的?