循环队列的两种写法

首先说一下主要思路:循环队列的关键就是区别队列满和空的
两个条件,因为是循环队列,空和满状态会是相同的!至于循环方式可以采用一个空闲单位的方式(x+1)%MaxSize,+1其实就浪费了MaxSize-1索引存储的数据。好了不多说看下写法吧!

下面展示一下第一种写法

第一种写法,比较普遍,这就是空闲单位法
思路:留一个空间作为区别队列空和满的判定
#include <stdio.h>

#define MaxSize 6
#define DataType int

typedef struct{
	DataType data[MaxSize];
	int front;
	int rear;
}SeQueue;

void InitSeQueue(SeQueue *q){
	q->rear=q->front=0;	
}

int EnQueue(SeQueue *q,int x){
	if(q->front==(q->rear+1)%MaxSize)
	/*这里判定条件说明一下,首先目的是为了防止超出队列空间。
	其次这个公式意思就是尾部到末尾再加上一正好回到起点,
	说明队满了。但这时浪费了一个位置就是MaxSize-1的这个位置,
	用来判断队满了!而如果采用队列为空q->front==q->rear来判
	断是否超出队列是不行的,因为队为空和队满都是一样的条件,
	会引起歧义。
	*/
		return false;
	else{
		q->data[q->rear]=x;
		q->rear=(q->rear+1)%MaxSize;//rear指向下一个位置,由于是循环可能超出上限所以采用这个公式。
		return true;
	}
	
}

int DeQueue(SeQueue *q,int &x){
	if(q->front==q->rear)//说明队列为空
		return false;
	else{
		x=q->data[q->front];
		q->data[q->front]=0; 
		q->front=(q->front+1)%MaxSize;//同理
		return true;
	}
}

int PrintSeQueue(SeQueue *q){
	while(q->front!=q->rear){//判断队列是否为空的条件
		printf("%d ",q->data[q->front]);
		q->front=(q->front+1)%MaxSize;
	}
}

int main(){
	SeQueue q;
	InitSeQueue(&q);//初始化
	for(int i=0;i<=4;i++)
		EnQueue(&q,i);//插入5个数
	PrintSeQueue(&q);//输出5个数
}

下面展示一下 第二种写法

第二种写法,可以更好利用了第一种写法浪费的空间,标记法。
思路:既然第一种写法浪费了空间,那么要利用第一种写法浪费的空间,我们就可以利用
好第一种写法的判断队列满的判定条件q->front==(q->rear+1)%MaxSize,说明q->rear+1
结尾前一个的这个空间没有用到,那么我们就有一个思路了,标记一个flag,把这个空间
利用起来,让判定条件认为这个地方是可以放入队列成员的!判定完后,再设个条件作为
判定队列已满的条件flag=1,那么就有了两个区别队列空和满的条件了!重点:判断为空的
条件是:flag==0&&q->front==q->rear 为满的条件:flag==1

(如果有更好的想法欢迎在评论区提出,我会努力修改的!)
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 6
#define DataType int
int flag = 0;//0表示队列未满,默认为0,1表示队列已满。

typedef struct{
	DataType data[MaxSize];
	int front;
	int rear;
}SeQueue;

void InitSeQueue(SeQueue *q){
	q->rear=q->front=0;	
}

int EnQueue(SeQueue *q,int x){
	if(flag==1){
		return false;//表示队列已满,无法插入。
	}
	if(q->front==(q->rear+1)%MaxSize){
	/*
	队列刚好到空闲的地方,插入后flag未0 ,表示已满!
	*/
		q->data[q->rear]=x;
		q->rear=(q->rear+1)%MaxSize;
		flag = 1;
		return true;
	}
		
	if(flag==0){
	 /*队列未满,直接插入。注意:这个条件不能用||加入到上面,
	否则flag后面直接=1就默认满了。
	*/
		q->data[q->rear]=x;
		q->rear=(q->rear+1)%MaxSize;
		return true;
	}
	
	
}

int DeQueue(SeQueue *q,int &x){
	if(q->front==q->rear&&flag!=1)//两个条件必须同时成立,说明队列为空!
		return false;
	else{
		x=q->data[q->front];
		q->data[q->front]=0;
		q->front=(q->front+1)%MaxSize;
		flag=0;//删除一个说明队列有空位置了
		return true;
	}
}

int PrintSeQueue(SeQueue *q){
	int flag1=flag;
	while(flag==1||q->front!=q->rear){
	/*
	说明队列为满或不为空
	注意:不可以改为flag==0
	因为队满的时候flag==1
	*/
		printf("%d ",q->data[q->front]);
		q->front=(q->front+1)%MaxSize;
		flag=0;
		/*
		把队列设为未满,是为了防止如果flag==1的话while一直循环下去!当然你
		设置个if条件判断也可以。
		*/
	}
	flag=flag1;//结束后flag设置原来状态
}

int main(){
	SeQueue q;
	int x;
	InitSeQueue(&q);//队列初始化
	for(int i=0;i<=5;i++)
		EnQueue(&q,i);//进队六个数据
	for(int i=0;i<=4;i++)
		DeQueue(&q,x);//出队五个数据
	PrintSeQueue(&q);//打印结果
}
<think>嗯,用户问的是链表和队列写法是不是结构体套结构体。我需要先回想一下链表和队列的基本结构。链表通常由节点组成,每个节点包含数据和指向下一个节点的指针,所以用结构体嵌套结构体可能是常见的做法。比如,定义一个节点结构体,里面包含数据和指向下一个节点的指针,而链表本身可能用一个结构体来管理头节点和其他信息,比如长度。这时候链表结构体里会嵌套节点结构体吗?或者可能只是用指针来引用节点? 队列的话,一般可以用数组或链表实现。如果用链表实现,可能类似链表的写法,有头尾指针;如果用数组的话,可能用循环队列的结构。所以队列的结构体可能包含两个节点指针(头尾)或者数组以及相关的索引。这时候结构体是否嵌套结构体呢? 用户的问题可能是在学习数据结构时,看到了一些用结构体嵌套的例子,所以想知道是不是必须这样。比如在C语言中,结构体不能包含自身类型的实例,但可以包含指向自身类型的指针,所以链表节点的结构体里会有一个指向自己类型的指针。而队列的结构体可能需要包含这样的节点结构体或者指针。 可能用户混淆了结构体的嵌套方式。比如,链表的结构体可能包含一个指向节点结构体的指针,而不是直接嵌套节点结构体。而节点结构体本身可能单独定义,然后被链表结构体引用。所以结构体套结构体可能指的是节点结构体被包含在链表结构体中吗?或者可能用户看到的是另一种写法? 需要举例说明链表和队列的常见写法。比如,链表节点定义为一个结构体,包含数据和next指针;而链表本身可能不需要单独的结构体,直接通过头指针操作,或者用一个结构体来包裹头指针和长度等信息。这时候链表结构体可能包含节点结构体的指针,而不是嵌套结构体本身。 队列如果用链表实现,结构体可能包含头尾指针,这些指针指向节点结构体。节点结构体是单独定义的,所以队列结构体里包含的是结构体指针,而不是嵌套的结构体实例。所以这种情况下,结构体是包含指针,而不是嵌套另一个结构体的实例。 但如果是另一种写法,比如在C++中使用类,可能内部有嵌套类的定义,比如队列类内部定义节点类,这时候可能结构体套结构体。但在C语言中,结构体不能嵌套定义,只能在外部先定义节点结构体,再在链表或队列的结构体中包含指向它的指针。 总结来说,链表和队列的实现通常涉及结构体,但更多是通过结构体包含指向同类型结构体的指针(链表节点),或者结构体包含其他结构体的指针或数组(队列的头尾指针或数组存储)。所以严格来说,结构体套结构体的情况可能存在,但更常见的是结构体包含指向其他结构体的指针,而不是直接嵌套结构体实例。 需要进一步解释结构体的定义方式,以及链表和队列的不同实现方法,比如链式队列和顺序队列的区别。用户可能对结构体的嵌套方式有误解,认为必须每层都嵌套,但实际可能更多是通过指针引用。因此,回答时要澄清这一点,给出具体例子,说明结构体如何定义,以及是否嵌套。</think>链表和队列的实现通常涉及结构体,但**不一定是“结构体套结构体”**,具体取决于编程语言和设计思路。以下是常见写法(以 C 语言为例): --- ### **1. 链表的实现** 链表的核心是**节点(Node)**,每个节点包含数据和指向下一个节点的指针。通常有两种设计方式: #### **方式 1:单独定义节点结构体** ```c // 定义节点结构体 struct Node { int data; struct Node* next; // 指向下一个节点的指针(不是嵌套结构体) }; // 链表本身通过头指针操作 struct Node* head = NULL; // 链表头 ``` #### **方式 2:链表包裹节点(可选)** ```c // 先定义节点 struct Node { int data; struct Node* next; }; // 再定义一个链表结构体(可选) struct LinkedList { struct Node* head; // 包含节点指针,而非嵌套结构体 int size; }; ``` **关键点**: - 节点结构体**包含指向自身类型的指针**,而非嵌套实例(否则会导致无限递归)。 - 链表可能直接操作节点指针,或通过一个外层结构体管理头节点和其他信息。 -- ### **2. 队列的实现** 队列的特点是“先进先出”,通常用**链表或数组**实现。两种常见写法: #### **链式队列(链表实现)** ```c // 先定义节点 struct Node { int data; struct Node* next; }; // 队列结构体:包含头尾指针 struct Queue { struct Node* front; // 队头指针 struct Node* rear; // 队尾指针 int size; }; ``` #### **顺序队列(数组实现)** ```c #define MAX_SIZE 100 struct ArrayQueue { int data[MAX_SIZE]; // 用数组存储元素 int front; // 队头索引 int rear; // 队尾索引 }; ``` **关键点**: - 链式队列通过**指针引用节点**,而非嵌套结构体。 - 顺序队列直接使用数组,无需嵌套结构体。 --- ### **总结** - **链表**和**队列**的实现**依赖结构体**,但通常通过**指针引用**或**数组**组织数据,而非直接嵌套结构体实例。 - 结构体嵌套常见于需要组合多种数据的场景(例如树节点包含子树),但需注意避免无限递归。 - 在面向对象语言(如 C++/Java)中,可通过类更直观地封装链表和队列的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值