数据结构——循环队列【c语言版】

 队列(quque)简称队,只允许在表的一端输入,在表的另一端删除(操作受限制的线性表),

把进行插入的一段叫做队尾(表尾),把进入删除的一端叫做队首或队头(表头)。

队列最主要的特点:先进先出,FIFO(first in first out)

队列有其实有三种:顺序队列、 循环队列、链式队列

       为了避免顺序队列中出现的假溢出现象,我们只需要把数组的前后端连接起来,形成一个环形数组,在逻辑上把这个环称为环形队列或者循环队列。

        下面是循环队列的实现过程:

        假设栈的元素个数最大不超过正整数MAXSIZE,所以元素具有同一数据类型(ElemType),用下来方式来声明循环队列的类型SQQueue:

#define MAXSIZE 10  //队列的最大容量

typedef int ElemType;  //队列中元素类型

typedef struct
{
	ElemType data[MAXSIZE];//存储值 
	int front;//存储队头元素前一个单元的下标 
	int rear;//存储队尾元素的下标 
}SQQueue;

对于循环队列来说,有以下四个非常重要的要素:

        1.队空条件:SQ->front == SQ->rear 

        2.队满条件:SQ->rear+1)%MAXSIZE == SQ->front

        3.进队操作:

                            SQ->rear = (SQ->rear + 1) % MAXSIZE;
                            SQ->data[SQ->rear] = e;                           

                            先将 SQ->rear = (SQ->rear + 1) % MAXSIZE,再将元素e放在rear指向的位置

        4.出队操作:

                            SQ->front = (SQ->front+1) % MAXSIZE;
                            *e = SQ->data[SQ->front];

                             先将 SQ->front = (SQ->front+1) % MAXSIZE,再将取出front指向的位置上的元                               素并存放于e中

1)队列初始化

        构造一个空的队列SQ,将front和rear指针都指向-1,代码如下:

void InitQueue(SQQueue* SQ)
{
	SQ->front = SQ->rear = -1;	
	
} 

2)判断队列是否为空

        注:为了区分空和满,任意时候都预留1个单元出来x的下一个:(x+1)%MAXSIZE

        循环队列中,判断队列是否为空,只需要判断SQ->front == SQ->rear的条件成立即可,代码如下:

//判断队列为空

void InitQueue(SQQueue* SQ)
{
	SQ->front = SQ->rear = -1;	
	
} 

3)判断队列是否为满

                循环队列中,判断队列是否为满,只需要判断(SQ->rear+1)%MAXSIZE == SQ->front的条件成立即可,

特别注意,循环队列中的特殊情况,初始状态下SQ->front == -1,当执行进队操作SQ->rear == MAXSIZE - 2时队列已满,需要将这一特殊情况考虑,代码如下:

int IsFUll(SQQueue* SQ)  //判断队列是否为满 
{	
	 //尾指针+1追上队头指针,标志队列已经满了
	if(((SQ->rear+1)%MAXSIZE == SQ->front)||(SQ->rear==MAXSIZE-2&&SQ->front==-1))
	{
		return 1;
	}
	return 0; //队不满 
}

4)入队

        在队列不满条件下先将rear+1,再将元素e放在rear指向的位置,因此该操作需要先判断操作合法性,若队列未满,执行相关操作,否则提示并返回0,这里可以调用IsFull(SQQueue* SQ)来判断,代码如下:


int EnterQueue(SQQueue* SQ,ElemType e)
{
	if (IsFUll(SQ))  // (SQ->rear + 1)%MAXSIZE == SQ->front
	{
		printf("队满,不能进队。\n"); 
		return 0;
	}
	SQ->rear = (SQ->rear + 1) % MAXSIZE;
	SQ->data[SQ->rear] = e;
}

5)出队

         这里需要先判断循环队列是否为空,若为空,提示并返回0,若不空则执行相关操作,         先将 SQ->front = (SQ->front+1) % MAXSIZE,再将取出front指向的位置上的元 素并存放于e中,这里可以调用IsEmpty(SQQueue* SQ)来判断,代码如下:

int DeleteQueue(SQQueue* SQ,ElemType* e)
{
	if (IsEmpty(SQ))
	{
		printf("队空,不能出队!\n");
		return 0;
	}
	SQ->front = (SQ->front+1) % MAXSIZE;
	*e = SQ->data[SQ->front];
}

6)求队列长度

代码如下:

int lenghtSQQueue(SQQueue* SQ)
{
	int len;
	len = 0;
	len = (SQ->rear-SQ->front+MAXSIZE)%MAXSIZE;	
	return len;
}

7)打印队列中的元素

        从队首到队尾,代码如下:

//打印队列中的与元素

void DispSQQueue(SQQueue* SQ)
{
	if (IsEmpty(SQ))
	{
		printf("队空!");
	}
	int i;
	i = SQ->front+1;
	printf("队列元素为:");
	while(i <= SQ->rear)
	{
		
		printf("%d ",SQ->data[i]); 
		i++;
	}
}

下面是入队、出栈和返回队列长度以及打印出队列元素的操作:

int main()
{
	SQQueue SQ;
	ElemType e;
	InitQueue(&SQ);
	
	//入队
	EnterQueue(&SQ,1);
	EnterQueue(&SQ,2);
	EnterQueue(&SQ,3);
	EnterQueue(&SQ,4);
	EnterQueue(&SQ,5);
	EnterQueue(&SQ,6);
	EnterQueue(&SQ,7);
	EnterQueue(&SQ,8);
	EnterQueue(&SQ,9);
	EnterQueue(&SQ,10);
	
	//打印队列元素 
	DispSQQueue(&SQ);
	printf("\n"); 
	printf("队列长度为:%d\n",lenghtSQQueue(&SQ)); 
	//出队
	DeleteQueue(&SQ,&e);
	printf("出队元素为:%d\n",e);
	DeleteQueue(&SQ,&e);
	printf("出队元素为:%d\n",e);
	
	//打印队列元素 
	DispSQQueue(&SQ);
	printf("\n"); 
	
	EnterQueue(&SQ,8);
	EnterQueue(&SQ,9);
	//打印队列元素 
	DispSQQueue(&SQ);
	printf("\n");
	EnterQueue(&SQ,10);

	
	printf("队列长度为:%d\n",lenghtSQQueue(&SQ)); 
	return 1;
} 

测试结果如下:

 

当元素10进栈时,队满提示,并返回队列元素,在将队首元素出栈两次,返回队列元素,再将元素8,9进队,再返回队列元素,此时再将元素10进队时提示队满,返回队列长度,自此,循环队列构造完成。

最后再附上完整代码:

#include <stdio.h>

#define MAXSIZE 10

typedef int ElemType;

typedef struct
{
	ElemType data[MAXSIZE];//存储值 
	int front;//存储队头元素前一个单元的下标 
	int rear;//存储队尾元素的下标 
}SQQueue;

/*
初始化:front=-1;rear=-1;

为了区分空和满,任意时候都预留1个单元出来
x的下一个:(x+1)%MAXSIZE
 
空:front==rear
满:(rear+1)%MAXSIZE==front

进队:
rear=(rear+1)%MAXSIZE;
data[rear]=e; 

出队:
front=(front+1)%MAXSIZE;
*e=data[front];
 
长度:
(rear-front+MAXSIZE)%MAXSIZE 
 
*/

/*
空:q->front==NULL && q->rear==NULL 
*/

void InitQueue(SQQueue* SQ)
{
	SQ->front = SQ->rear = -1;	
	
} 

int IsEmpty(SQQueue* SQ)  //判断队列是否为空 
{
	if (SQ->front == SQ->rear)
	{
		return 1;  //队空 
	}
	return 0;
}

int IsFUll(SQQueue* SQ)  //判断队列是否为满 
{	
	 //尾指针+1追上队头指针,标志队列已经满了
	if(((SQ->rear+1)%MAXSIZE == SQ->front)||(SQ->rear==MAXSIZE-2&&SQ->front==-1))
	{
		return 1;
	}
	return 0; //队不满 
}

int EnterQueue(SQQueue* SQ,ElemType e)
{
	if (IsFUll(SQ))  // (SQ->rear + 1)%MAXSIZE == SQ->front
	{
		printf("队满,不能进队。\n"); 
		return 0;
	}
	SQ->rear = (SQ->rear + 1) % MAXSIZE;
	SQ->data[SQ->rear] = e;
}

int DeleteQueue(SQQueue* SQ,ElemType* e)
{
	if (IsEmpty(SQ))
	{
		printf("队空,不能出队!\n");
		return 0;
	}
	SQ->front = (SQ->front+1) % MAXSIZE;
	*e = SQ->data[SQ->front];
}

int lenghtSQQueue(SQQueue* SQ)
{
	int len;
	len = 0;
	len = (SQ->rear-SQ->front+MAXSIZE)%MAXSIZE;	
	return len;
}

void DispSQQueue(SQQueue* SQ)
{
	int index;
	int i;
	
	i = 1;
	index=(SQ->front+1)%MAXSIZE;
	printf("队列元素为:");
	while(i <= lenghtSQQueue(SQ))
	{
		printf("%d ",SQ->data[index]);
		index=(index+1)%MAXSIZE; 
		
		i++;
	}
}

int main()
{
	SQQueue SQ;
	ElemType e;
	InitQueue(&SQ);
	
	//入队
	EnterQueue(&SQ,1);
	EnterQueue(&SQ,2);
	EnterQueue(&SQ,3);
	EnterQueue(&SQ,4);
	EnterQueue(&SQ,5);
	EnterQueue(&SQ,6);
	EnterQueue(&SQ,7);
	EnterQueue(&SQ,8);
	EnterQueue(&SQ,9);
	EnterQueue(&SQ,10);
	
	//打印队列元素 
	DispSQQueue(&SQ);
	printf("\n"); 
	printf("队列长度为:%d\n",lenghtSQQueue(&SQ)); 
	//出队
	DeleteQueue(&SQ,&e);
	printf("出队元素为:%d\n",e);
	DeleteQueue(&SQ,&e);
	printf("出队元素为:%d\n",e);
	
	//打印队列元素 
	DispSQQueue(&SQ);
	printf("\n"); 
	
	EnterQueue(&SQ,8);
	EnterQueue(&SQ,9);
	//打印队列元素 
	DispSQQueue(&SQ);
	printf("\n");
	EnterQueue(&SQ,10);

	
	printf("队列长度为:%d\n",lenghtSQQueue(&SQ)); 
	return 1;
} 

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值