第三章-队列(2)循环队列

本文深入讲解了循环队列的概念及其实现方式,包括初始化、基本操作(如插入、删除元素等),并探讨了如何判断队列为空或满的方法。通过具体的代码示例,帮助读者更好地理解循环队列的工作原理。
循环队列
-------------------------------------------------------------------------------------------------------------------
和顺序栈相类似,在队列的顺序储存结构中,除了用一组地址连续的存储单元依次存放从队头到队列尾的元素之外,还需设两个指针 Q.front 和 Q.rear 分别指向队列头元素和队列尾元素。
   初始化队列的时候, 令   front=rear=1, 每当插入新的元素的时候的时候, rear增加1,每当删除元素的时候, front增加1。 

       
                                        

如图3.13,称之为循环队列。


         



如图 a :队列头元素是 J3 ,队列尾元素是 J5.
如图 b :Q.front=Q.rear,队列是满的。
如图 c :Q.front=Q.rear ,队列为空。

(注: Q.front=Q.rear无法判定队列空间是 “空”还是“满”,)
  有两种方法: 
               1、另设一个标志位以区别队列是“空”还是“满”。
               2、少用一个元素空间,约定以“队列头指针在队列尾指针的下一位置(指环状的下一位置)上”作为       队列呈“满”状态的标志。        



代码:
//头文件  
#include"stdio.h" 
#include"stdlib.h"
#include"malloc.h" 

//宏定义  
#define TRUE 1
#define FALSE 0  
#define OK 1  
#define ERROR 0  
#define INFEASIBLE -1  
#define OVERFLOW -2  
  
typedef char QElemType;  
typedef char Status;  
//---------循环队列——队列的顺序存储结构---------
#define MAXQSIZE 100   //最大队列长度

typedef struct{
	QElemType *base;    //初始化的动态分配存储空间
	int front;          //头指针,若队列不为空,指向队列的头元素
	int rear;           //尾指针,若队列不为空,指向队列尾元素的下一个位置
}SqQueue;

//--------循环队列的基本操作的算法描述-------------
//1、初始化循环队列
Status InitQueue(SqQueue &Q){
	//构造一个空队列Q
	Q.base=(QElemType *)malloc(MAXQSIZE*sizeof(QElemType));
	if(!Q.base) exit(OVERFLOW);     //存储分配失败
	Q.front=Q.rear=0;
	return OK;
}

//2、求循环队列的长度,返回 Q 的元素个数,即队列的长度 
Status QueueLength(SqQueue Q){
	return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
}

//3、插入元素e为 Q 的新的元素
Status EnQueue(SqQueue Q,QElemType e){
	if((Q.rear+1)%MAXQSIZE == Q.front)
		return ERROR;    //队列满
	Q.base[Q.rear]=e;
	Q.rear=(Q.rear+1)%MAXQSIZE;
	return OK;
}

//4、若队列不为空,则删除 Q 的队头元素,用 e 返回其值,并返回OK ,否则返回ERROR
Status DeQueue(SqQueue &Q,QElemType &e){
	if(Q.front==Q.rear) return ERROR;
	e=Q.base[Q.front];
	Q.front=(Q.front+1)%MAXQSIZE;
	return OK;
}


Status GetTop(SqQueue &Q, QElemType &e)  
{  
       if (Q.rear == Q.front)  
		   return ERROR;  
       e = Q.base[Q.front];  
           return OK;  
} 
Status Destroy(SqQueue Q){
	free(Q.base);
	Q.base=NULL;
	return OK;
}












### 另类循环队列的实现方法 #### 队列的基本概念 队列是一种特殊的线性表,遵循先进先出(FIFO, First In First Out)的原则。通常情况下,队列有两个指针:`Front` 和 `Rear`,分别指向队首和队尾。然而,在“另类循环队列”的设计中,仅设置一个头指针 `Front` 来标记队首位置,并通过额外变量 `Count` 记录当前队列中的元素数量。 这种设计的核心在于利用循环数组来模拟队列的行为,同时省去了显式的尾指针 `Rear` 的维护工作[^1]。 --- #### 数据结构定义 以下是该数据结构的关键组成部分: - **数组 Data[]**:用于存储队列中的元素。 - **整型 Front**:指示队列头部的位置。 - **整型 Count**:记录队列中实际存在的元素个数。 - **常量 MaxSize**:表示队列的最大容量。 --- #### 入队操作 (`AddQ`) 入队操作是指向队列中添加新元素的过程。具体逻辑如下: 1. 判断队列是否已满(即 `Count >= MaxSize`)。如果已满,则返回失败标志。 2. 如果未满,计算下一个可用位置 `(Front + Count) % MaxSize` 并将新元素存入此位置。 3. 增加计数器 `Count`。 4. 返回成功标志。 代码实现如下: ```c bool AddQ(Queue Q, ElementType X) { if (Q->Count == MaxSize) { // 检查队列是否已满 return false; } int rear = (Q->Front + Q->Count) % MaxSize; // 计算队尾索引 Q->Data[rear] = X; // 插入元素到队尾 Q->Count++; // 更新元素计数 return true; } ``` 上述代码实现了动态调整队尾位置的功能,而无需显式维护 `Rear` 指针[^2]。 --- #### 出队操作 (`DeleteQ`) 出队操作是从队列中移除并返回最前面的元素。其主要步骤为: 1. 判断队列是否为空(即 `Count == 0`)。如果是空队列,则无法执行出队操作。 2. 获取当前队首元素 `Q->Data[Q->Front]`。 3. 将头指针向前移动一位(考虑循环特性),更新为 `(Front + 1) % MaxSize`。 4. 减少计数器 `Count`。 5. 返回被移除的元素。 代码实现如下: ```c ElementType DeleteQ(Queue Q) { if (Q->Count == 0) { // 检查队列是否为空 exit(EXIT_FAILURE); // 或者抛出异常处理机制 } ElementType value = Q->Data[Q->Front]; // 获取队首元素 Q->Front = (Q->Front + 1) % MaxSize; // 移动头指针 Q->Count--; // 更新元素计数 return value; } ``` 注意,当尝试从空队列中删除元素时,应采取适当措施防止程序崩溃或错误行为发生[^3]。 --- #### 初始化与边界条件 为了确保队列能够正常运行,初始化阶段需特别关注以下几个方面: 1. 设置初始状态:`Front = 0`, `Count = 0`。 2. 循环数组的实际顺序可能不同于直观理解,例如从最后一个有效位置回到起始位置时会经过零下标。 3. 所有涉及索引的操作均需取模运算 `% MaxSize`,以保持循环性质。 --- #### 性能分析 - 时间复杂度:无论是入队还是出队操作,时间复杂度均为 O(1),因为每次只需修改固定数量的状态值即可完成任务。 - 空间复杂度:由于采用定长数组作为底层容器,空间开销取决于预分配大小 `MaxSize`。 --- ### 示例应用 假设我们创建了一个最大容量为 5 的队列实例,并依次调用以下函数: ```c Queue q = CreateQueue(); // 创建队列对象 AddQ(q, 10); AddQ(q, 20); printf("%d\n", DeleteQ(q)); // 输出 10 AddQ(q, 30); ``` 最终队列内的元素序列为 `[20, 30]`,其中 `Front` 指向第二个位置,`Count` 表示两个元素存在。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值