3.2 队列

本文深入探讨了队列这一基本数据结构,包括其定义、工作原理、常用操作(如入队、出队)以及在计算机科学中的应用。通过实例解析,帮助读者理解队列在解决各种问题中的核心作用。
一、队列的概念
1.队列,一种操作受限的线性表,只允许在一端插入,在另一端删除。其操作特性是先进先出。
队头。允许删除的一端。
队尾。允许插入的一端。
空队列。不含任何元素的空表。

2.队列常见的基本操作。
InitQueqe(&Q):初始化队列,构造一个空队列Q
QueueEmpty(Q):判队列空,若队列Q为空则返回true,否则返回false
EnQueue(&Q,x):入队,若队列Q未满,将x加入,使之成为新的队尾
DeQueue(&Q,&x):出队,若队列Q非空,删除队头元素,并用x返回
GetHead(Q,&x):读对头元素,若队列Q非空,则将队头元素赋值给x

二、队列的顺序存储结构
1.队列的顺序存储
	队列的顺序实现是指分配一块连续的存储单元存放队列中的元素,并附设两个指针:队头指
针front指向队头元素,队尾指针rear指向队尾元素的下一个位置。
	队列的顺序存储类型可描述为
	#define MaxSize 50							//定义队列中元素的最大个数
	typedef struct{
	ElemType data[MaxSize];						//存放队列元素
	int front,rear;								//队头指针和队尾指针
	}SqQueue;
	初始状态(队空条件):Q.front==Q.rear==0
	进队操作:队不满时,先送值到队尾元素,再将队尾指针+1
	出队操作:队不空时,先取队头元素值,再将队头指针+1

2.循环队列
	将顺序队列臆造为一个环状的空间,称为循环队列。当队首指针Q.front=MaxSize-1后,再
前进一个位置就自动到0,这可利用除法取余运算来实现。
	初始时:Q.front=Q.rear=0
	队首指针进1:Q.front=(Q.front+1)%MaxSize
	队尾指针进1:Q.rear=(Q.rear+1)%MaxSize
	队列长度:(Q.rear+MaxSize-Q.front)%MaxSize
	
	为了区分队空还是队满的情况,有三种处理方式
	(1)牺牲一个单元来区分队空和队满,入队时少用一个队列单元
	队满条件:(Q.rear+1)%MaxSize==Q.front
	队空条件:Q.front==Q.rear
	队列中元素的个数:(Q.rear+MaxSize-Q.front)%MaxSize

	(2)类型中增设表示元素个数的数据成员。这样,队空的条件为Q.size==0;队满的条件为
Q.size==MaxSize.

	(3)类型中增设tag数据成员。tag=0时,若因删除导致Q.front==Q.rear,则为队空;
tag=1时,若因插入导致Q.front==Q.rear则为队满。

3.循环队列的操作
(1)初始化
	void InitQueue(SqQueue &Q){
		Q.front=Q.rear=0;			//初始化队首、队尾指针
	}

(2)判队空
	bool isEmpty(SqQueue Q){
		if(Q.front==Q.rear)
			return true;
		else
			return false;
	}

(3)入队
	bool EnQueue(SqQueue &Q,ElemType x){
		if(Q.rear+1)%MaxSize==Q.front)
			return false;				//队满报错
		Q.data[Q.rear]=x;
		Q.rear=(Q.rear+1)%MaxSize;		//队尾指针加1取模
		return true;
	}

(4)出队
	bool DeQueue(SqQueue &Q,ElemType &x){
		if(Q.rear==Q.front)
			return false;		//队空则报错
		x=Q.data[Q.front];
		Q.front=(Q.front+1)%MaxSize;	//队头指针加1取模
		return true;
	}

三、队列的链式存储结构
1.队列的链式存储
	队列的链式表示称为链队列,它实际上是一个同时带有队头指针和队尾指针的单链表。头指
针指向队头结点,尾指针指向队尾结点,即单链表的最后一个结点。
	队列的链式存储类型可描述为
	typedef struct{					//链式队列结点
		ElemType data;
		struct LinkNode *next;
	}LinkNode;
	typedef struct{					//链式队列
		LinkNode *front,*rear;		//队列的队头和队尾指针
	}LinkQueue;
	当Q.front==NULL且Q.rear==NULL时,链式队列为空。

2.链式队列的基本操作
(1)初始化
	void InitQueue(LinkQueue &Q){
		Q.front=Q.rear=(LinkNode*)malloc(sizeof(LinkNode));//建立头结点
		Q.front->next=NULL;		//初始为空
	}

(2)判队空
	bool IsEmpty(LinkQueue Q){
		if(Q.front==Q.rear)
			return true;
		else
			return false;
	}

(3)入队
	void EnQueue(LinkQueue &Q,ElemType x){
		LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
		s->data=x;
		s->next=NULL;	//创建新结点,插入到链尾
		Q.rear->next=s;
		Q.rear=s;
	}

(4)出队
	bool DeQueue(LinkQueue &Q,ElemType &x){
		if(Q.front==Q.rear)
			return false;//空队
		LinkNode *p=Q.front->next;
		x=p->data;
		Q.front->next=p->next;
		if(Q.rear==p)
			Q.rear=Q.front;//若原队列中只有一个结点,删除后变空
		free(p);
		return true;
	}

四、双端队列
	双端队列是指允许两端都可以进行入队和出队操作的队列。
	输出受限的双端队列:允许在一端进行插入和删除,但在另一端只允许插入
	输入受限的双端队列:允许在一端进行插入和删除,但在另一端只允许删除
以下是实现最大长度为5的顺序队列,包含初始化队列、判断队列是否为空、判断队列是否已满、入队操作、出队操作、获取队头元素、获取队列长度、打印队列所有元素等操作的代码,同时包含主函数测试这些操作,并展示队列满和队列空的情况: ```c #include <stdio.h> #include <stdlib.h> #define Maxsize 5 typedef struct { int data[Maxsize]; int front, rear; } SqQueue; // 初始化队列 void InitQueue(SqQueue &Q) { Q.front = Q.rear = 0; } // 判断队列是否为空 bool isEmpty(SqQueue Q) { if (Q.front == Q.rear) { return true; } return false; } // 判断队列是否已满 bool isFull(SqQueue Q) { if ((Q.rear + 1) % Maxsize == Q.front) { return true; } return false; } // 入队操作 bool EnQueue(SqQueue &Q, int x) { if (isFull(Q)) { return false; } Q.data[Q.rear] = x; Q.rear = (Q.rear + 1) % Maxsize; return true; } // 出队操作 bool DeQueue(SqQueue &Q, int &x) { if (isEmpty(Q)) { return false; } x = Q.data[Q.front]; Q.front = (Q.front + 1) % Maxsize; return true; } // 获取队头元素 bool GetFront(SqQueue Q, int &x) { if (isEmpty(Q)) { return false; } x = Q.data[Q.front]; return true; } // 获取队列长度 int GetLength(SqQueue Q) { return (Q.rear - Q.front + Maxsize) % Maxsize; } // 打印队列所有元素 void PrintQueue(SqQueue Q) { if (isEmpty(Q)) { printf("队列空,无元素可打印。\n"); return; } int i = Q.front; while (i != Q.rear) { printf("%d ", Q.data[i]); i = (i + 1) % Maxsize; } printf("\n"); } int main() { SqQueue S; InitQueue(S); // 展示队列为空的情况 printf("队列为空的情况:\n"); if (isEmpty(S)) { printf("队列是空的。\n"); } PrintQueue(S); // 入队操作,将队列填满 printf("\n将队列填满的情况:\n"); for (int i = 1; i <= Maxsize - 1; i++) { EnQueue(S, i); } if (isFull(S)) { printf("队列已满。\n"); } PrintQueue(S); // 获取队头元素 int frontElement; if (GetFront(S, frontElement)) { printf("队头元素是:%d\n", frontElement); } // 获取队列长度 printf("队列长度是:%d\n", GetLength(S)); // 出队操作,将队列清空 printf("\n将队列清空的情况:\n"); int dequeuedElement; while (DeQueue(S, dequeuedElement)) { printf("出队元素:%d\n", dequeuedElement); } if (isEmpty(S)) { printf("队列已清空。\n"); } PrintQueue(S); return 0; } ``` ### 代码解释 1. **初始化队列**:将队列的头指针和尾指针都置为0,表示队列为空。 2. **判断队列是否为空**:当队头指针和队尾指针相等时,队列为空。 3. **判断队列是否已满**:当队尾指针的下一个位置是队头指针时,队列已满。 4. **入队操作**:在队列不满的情况下,将元素放入队尾,并将队尾指针向后移动一位。 5. **出队操作**:在队列不为空的情况下,取出队头元素,并将队头指针向后移动一位。 6. **获取队头元素**:在队列不为空的情况下,返回队头元素的值。 7. **获取队列长度**:通过计算队尾指针和队头指针的差值得到队列的长度。 8. **打印队列所有元素**:从队头指针开始,依次打印队列中的元素,直到队尾指针。 ### 主函数测试 主函数中首先展示了队列为空的情况,然后进行入队操作将队列填满,展示队列满的情况,接着获取队头元素和队列长度,最后进行出队操作将队列清空,展示队列空的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值