数据结构(C语言)-循环队列基本操作

文章首发于 2020-10-15 知乎文章:数据结构(C语言)-循环队列基本操作

作者:落雨湿红尘(也是我o)

导语

队列是一种先进先出(first in first out,FIFO)的线性表,是一种常用的数据结构。

它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。

                                                                                                    图1 队列

队列有很多种,按照存储结构划分,有链式队列,循环队列,单向队列,双端队列。实现队列的方式也有很多种,如基于链式存储结构的链接队列(又称链队列),基于顺序存储结构的队列。

本文介绍基于数组(一种顺序存储结构)的循环队列的实现和一些基本操作,并用代码的形式讲解

一些概念

队列的顺序存储结构和顺序栈类似

在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾的元素之外,还需要设置头尾两个指针front和rear,分别指示队列头元素及队尾元素的位置

我们规定

  • 初始化建立空队列时,令front=rear=0
  • 每当插入新的队尾元素时,“尾指针增1”
  • 每当删除队头元素时,“头指针增1”
  • 在非空队列中,头指针始终指向队列头元素,尾指针始终指向队列尾元素的下一个位置

                                       图2 队列的顺序存储结构

在入队和出队的操作中,头尾指针只增加不减小,致使被删除元素的空间永远无法重新利用,因此,尽管队列中实际的元素个数远远小于向量空间的规模,但也可能由于尾指针巳超出向量空间的上界而不能做入队操作,该现象称为假溢出

解决办法:将顺序队列臆造为一个环状的空间,称之为循环队列

循环队列

循环队列的结构如下图所示

                                   

                                                                                   图2 循环队列

以下代码,实现了一个可以保存学生学号(最长12位的字符串)循环队列,基于数组这种顺序存储结构,,实现了它的初始化,出队,入队,队列销毁的操作

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define OK 1
#define NO 0
#define MAXSIZE 100

//循环队列结构
typedef struct LoopQueue{
	char* base[MAXSIZE];//数据域由一个char*数组构成
	int front;//队头索引,指向队列第一个数据所在位置
	int rear; //队尾索引,指向队列最后一个数据后一个位置
}LoopQueue; 

//循环队列初始化。该循环队列基于数组,因此一旦声明一个LoopQueue变量
//其内部的base数组空间便自动分配,不需要自己分配
//只需初始化队头和队尾索引
int initLQueue(LoopQueue *Q){
	Q->front = Q->rear =0;
	return OK; 
}

//返回长度
int getLenth(LoopQueue *Q) {
	return (Q->rear - Q->front + MAXSIZE)%MAXSIZE;
}

//插入元素
int insertLQueue(LoopQueue *Q){
	
        //这里牺牲掉了一个储存位置,用rear+1来和队头索引相比较以判断是否为满,
        //是为了和队列判空条件相区分
       //判断队列是否 满,如果已满,返回NO
	if((Q->rear+1)%MAXSIZE == Q->front) return NO;
	char * stuId = (char*)malloc(sizeof(12));
	scanf("%s",stuId) ;
	Q->base[Q->rear] = stuId;
	Q->rear = (Q->rear+1)%MAXSIZE; 
	return  OK;
} 

//元素出队
char* outLQueue(LoopQueue *Q){
	//判断队列是否为空 
	if(Q->rear ==Q->front) return NULL;
	char * data_return = Q->base[Q->front];
	Q->front = (Q->front+1)%MAXSIZE; 
	return data_return; 
} 

//销毁队列,也是由于该循环队列基于数组,不需要分配内存
//只需重置队头和队尾索引即可
int destroyLQueue(LoopQueue *Q){
	Q->front = Q->rear=0; 
	return OK; 
}

//打印队列
void displayLQueue(LoopQueue *Q) { 
	if(Q->rear ==Q->front) printf("队列为空\n"); 
	//只要队列不为空 ,就从队头开始打印
	int p = Q->front,num=1; 
	while(p !=Q->rear){
		printf("第%d个学生学号:%s \n",num++,Q->base[p]); 
		p = (p+1)%MAXSIZE;
	}
	 
}

int main(){
	
	// 初始化队列 	
	LoopQueue Q;

	//定义一个选择变量 
	int choice;
	
	//元素插入个数 
	int num; 
	
	//出队返回值
	char* back; 
	do{	
		printf("===========循环队列操作==========\n");
		printf("1.初始化循环队列\n");
		printf("2.元素入队\n");
		printf("3.元素出队\n");
		printf("4.销毁队列\n");
        printf("5.打印队列\n");
		printf("0.退出\n");
		printf("=====================\n");
		printf("请输入您的选择:");
		scanf("%d",&choice);
			switch(choice){
				case 1:
					initLQueue(&Q)?printf("------------\n -->> 循环队列初始化成功\n------------\n"):printf("------------\n -->> 循环队列初始化失败\n------------\n");
					break;
				case 2:
					
				printf("请输入插入元素个数:");
				scanf("%d",&num);
				int i;
    			for(i=0;i<num;i++){	
					printf(" 请输入第%d个学生的学号:",i+1);			  								      
					if(!insertLQueue(&Q))printf("------------\n-->> 第%d元素入队失败\n",i+1);
				} 
				
					break;
				case 3:
					back = outLQueue(&Q);
					back? printf("------------\n 元素: %s 出队,还剩%d个元素\n",back,getLenth(&Q)):printf("------------\n队列为空,无法出队!\n"); 
	                free(back);	//回收内存,防止内存泄露(感谢评论区朋友提醒)			
					break;
				case 4:
					destroyLQueue(&Q)?printf("------------\n队列销毁成功!\n"):printf("------------\n队列销毁失败!\n");
					break;
                case 5:
					displayLQueue(&Q);
					break;
				case 0:
					printf("\n-->> 退出\n"); 
					exit(0);
					break;	
				default:
				 break; 
			}
	}while(choice);
	
	
}

以上代码经过调试,我自认为没有问题(鄙人才疏学浅,欢迎指正)

如果读者朋友们有疑问和更正,欢迎评论区补充和探讨

  • 14
    点赞
  • 112
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
循环队列是一种特殊的队列,其特点是队列的元素在物理结构上是环形排列的。educoder实训教学平台提供了循环队列基本操作,包括初始化、入队、出队和判空等。 循环队列的初始化操作是创建一个空队列,并设置队列的头指针和尾指针都为0。入队操作是往队尾插入一个元素,插入后尾指针向后移动一位,并将元素放入新的队尾位置。出队操作是将队首元素删除,删除后头指针向后移动一位。判空操作是通过比较队列的头指针和尾指针是否相等来确定队列是否为空。 链队列是使用链表实现的队列,其特点是可以动态地分配内存空间,不会造成内存溢出的问题。educoder实训教学平台也提供了链队列基本操作,包括初始化、入队、出队和判空等。 链队列的初始化操作是创建一个空队列,并设置头指针和尾指针都指向空节点。入队操作是在链队列的尾部插入一个新节点,尾指针向后移动一位,并将新节点的数据放入新的尾节点。出队操作是删除链队列的头节点,头指针向后移动一位。判空操作是通过判断链队列的头指针和尾指针是否指向同一节点来确定队列是否为空。 通过educoder实训教学平台提供的循环队列和链队列基本操作,学习者可以掌握数据结构队列的实现方式和基本操作的原理,进而应用于解决一些实际问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落雨湿红尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值