数据结构之顺序队列

数据结构之队列

什么是队列

  • 队列是和栈一样操作受限的线性表,栈是只允许在线性表的一端进行入栈和出栈操作,而队列是会允许在线性表的一端进行入队,在另外一端进行出队操作

队列的基本操作

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); // 判断队列是否为空

顺序队列

  • 用静态数组实现的队列(使用顺序存储结构实现的队列)缺点:空间固定
    image-20251022001229395

顺序队列的代码实现

#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;
}

代码缺陷

上述代码实现的队列,会浪费一个存储空间,如何避免浪费一个存储空间呢?

  1. 使用一个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--;
}
  1. 使用一个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. 输出受限的双端队列: 只允许一段进行删除,两段允许插入的线性表

image-20251022002020034

练习题:判断输出序列合法性

若数据元素输入序列为1,2,3,4,5 则哪些输出序列是合法的,哪些是非法的?

posted on 2025-10-22 00:33  jie_code  阅读(5)  评论(0)    收藏  举报

导航