0
点赞
收藏
分享

微信扫一扫

数据结构之顺序循环队列的基本操作(非常详细C语言版)

诗与泡面 2022-04-13 阅读 55

数据结构之顺序循环队列的基本操作(非常详细C语言版)

1.排忧解惑:

2.代码实现

# include <stdio.h>
# include <malloc.h>//使用malloc()函数必须引入的库


#define MAXQSIZE 5 //定义Q队列的最大长度,相当于一个数组arr[100]就是arr[MAXSIZE] 
#define OK 1  		 //定义返回状态码 return OK就是return 1    		在函数正确执行完的时候用 
#define ERROR 0		 //定义返回状态码 return ERROR就是return 0 		
#define OVERFLOW -2	 //定义返回状态码 return OVERFLOW就是return -2  在内存溢出的时候用 

typedef int QElemType;//定义下面代码中出现的QElemType就是表示int
typedef int Status; //定义下面代码中出现的Status就是表示int
//队列结构体的定义
typedef struct {
	QElemType * base;//指向动态分配内存的首地址
	int front;//头指针
	int rear;//尾指针

} SqQueue;

//1.队列初始化
Status InitQueue(SqQueue &Q) {
	Q.base = (QElemType *)malloc(MAXQSIZE*sizeof(QElemType));//动态创建连续的内存空间并将此内存空间的首地址赋给Q队列的base指针,即Q队列的base指针指向了这块连续的内存空间
	if(!Q.base) { //判断能不能在内存中找到这样一块连续空间,没有找到就exit(OVERFLOW),即返回状态OVERFLOW
		printf("内存溢出,无法开辟空间!");
		return OVERFLOW;
	}
	//如果找到了,就让Q队列的头指针和尾指针都等于0,即指向base[]数组的0的位置,即那块内存空间的首地址
	Q.front=Q.rear=0;
	printf("初始化队列成功!\n");
	//返回状态OK
	return OK;
}

//2.入队
Status EnQueue(SqQueue &Q) {
	//入队的时候首先需要判断队列是否满了

	if((Q.rear+1)%MAXQSIZE==Q.front) {
		printf("当前队满!\n");
		return OVERFLOW;
	}

	int input;//定义input变量接收用户输入的入队元素,用int声明的变量的空间是由系统自动分配的,当然这里也可以使用malloc动态创建内存空间
	printf("请输入入队元素:\n");
	scanf("%d",&input);
	Q.base[Q.rear] = input;//从队尾入队,把输入的数据放到Q队列的base数组的下标为Q.rear的位置
	Q.rear = (Q.rear+1)%MAXQSIZE;//rear++,这里的++在循环队列中要用(Q.rear+1)%MAXQSIZE,来解决假溢出的问题

	return OK;
}

//3.出队
Status DeQueue(SqQueue &Q) {
	//出队的时候首先判断队列是否为空		当然这里可以直接使用已经写好的判断队空的QueueEmpty()函数
	if(Q.front==Q.rear) {
		printf("当前队空,请先入队!\n");
		return ERROR;
	}
	int output;
	output = Q.base[Q.front];//从队头入队,记录出队数据
	//front++,同样这里的++在循环队列中要用(Q.front+1)%MAXQSIZE,来解决假溢出的问题
	Q.front = (Q.front+1)%MAXQSIZE;
	//打印出队元素
	printf("出队元素为:%d\n",output);
	return OK;
}

//4.取队头元素
Status GetHead(SqQueue &Q) {
	//队列不空的时候才能取队头元素		当然这里可以直接使用已经写好的判断队空的QueueEmpty()函数
	if(Q.front==Q.rear) {
		printf("当前队空,请先入队!\n");
		return ERROR;
	}
	int head;
	head = Q.base[Q.front];//将当前队头元素的值赋给head变量
	printf("当前队头元素为:%d\n",head);
	return OK;
}

//5.判断队列是否为空
Status QueueEmpty(SqQueue &Q) {
	//直接把上面出队时的判空逻辑复制过来,因为判断条件都是一样的
	if(Q.front==Q.rear) {
		printf("当前队空,请先入队!\n");
		return ERROR;
	}
	printf("当前队列不为空\n");//否则当前队列不为空
}

//6.遍历队列中的元素TravelQueue
Status TravelQueue(SqQueue &Q) {
	//先判断队列是否为空   		当然这里可以直接使用已经写好的判断队空的QueueEmpty()函数
	if(Q.front==Q.rear) {
		printf("当前队空,请先入队!\n");
		return ERROR;
	}
	//为防止遍历一次就把Q中的rear或者front的值修改,所以这里新建一个变量来接受rear或front的值
	//当然不想重新定义一个变量来保存front的值的话,可以在该函数的参数部分改为(SqQueue Q),
	//但是这样相当于在内存中重新拷贝了一份Q,而且每次遍历都会这样拷贝一份,内存开销大,速度和效率都会降低
	int front2 = Q.front;
	printf("当前队列中的元素为:");
	while(!(front2==Q.rear)) {
		printf("%d  ",Q.base[front2]);//输出当前base[front2]所表示的元素
		front2=(front2+1)%MAXQSIZE;//让front2表示下一次所在的位置
	}
	printf("\n");
	return OK;
}

//7.求当前队列长度
Status QueueLength(SqQueue &Q) {
	//printf("当前队列的长度:%d\n",(Q.rear-Q.front+MAXQSIZE)%MAXQSIZE);
	return OK;
}

//8.销毁队列DestroyQueue
Status DestoryQueue(SqQueue &Q) {
	//让front和rear相等即可
	Q.front=Q.rear;
	printf("队列销毁成功!"); 
	return OK;
}

int main(void) {
	SqQueue Q;//创建一个队列结构体Q
	int option;//变量option用于判断用户选择的栈操作
	int loop=1;//变量loop表示循环的条件
	do {
		//菜单
		printf("1.初始化队列\n");
		printf("2.判断当前队列是否为空\n");
		printf("3.入队\n");
		printf("4.出队\n");
		printf("5.取队头元素\n");
		printf("6.获取当前队列长度\n");
		printf("7.遍历队列中元素\n");
		printf("8.销毁队列\n");
		printf("9.退出系统\n");
		printf("请输入你的操作:");
		scanf("%d",&option);
		switch(option) {
			case 1://初始化队列
				InitQueue(Q);//调用初始化队列的函数,传入Q这个队列
				break;
			case 2://判断当前队列是否为空
				QueueEmpty(Q);
				break;
			case 3://入队
				EnQueue(Q);
				break;
			case 4://出队
				DeQueue(Q);
				break;
			case 5://取队头元素
				GetHead(Q);
				break;
			case 6://获取当前队列长度
				QueueLength(Q);
				break;
			case 7://遍历队列中元素
				TravelQueue(Q);
				break;
			case 8://销毁队列
				DestoryQueue(Q);
				break;
			case 9://退出系统
				loop = 0;
				printf("你退出了系统......");
		}
		printf("\n\n"); //每次执行完换两行,对用户视觉友好
	} while(loop);//循环条件为loop
}
举报

相关推荐

0 条评论