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

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

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

 

导语

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

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

                                 

                                                                  队列结构

队列有很多种,按照存储结构划分,有链式队列,循环队列,单向队列,双端队列

实现队列的方式也有很多种,如基于链式存储结构的链接队列(又称链队列),基于顺序存储结构的队列

本文介绍链队列的实现和一些基本操作,并用代码的形式讲解

 

一些概念

 

  1. 一个链队列需要两个指针才能唯一确定,它们分别指示队头和队尾(分别称为头指针和尾指针)
  2. 与线性表的单链表一样,为了操作方便起见, 给链队列添加一个头结点,并令头指针指向头结点
  3. 空的链队列的判别条件为头指针和尾指针均指向头结点

图2 队列的链式存储结构(链队列)

 

链队列的操作

 

以下代码实现了一个可以保存学生学号(最长12位的字符串)链队列,实现了它的初始化,出队,入队,队列销毁的操作:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define OK 1
#define NO 0
//OK和NO是自定义的状态变量

//链队列结点
typedef struct Qnode{
	char* data;//数据域
	struct Qnode *next;//指针域,指向下一个结点
}Qnode;

//链队列
typedef struct{
	Qnode* front;//队头指针 相当于Qnode *front 
	Qnode* rear;//队尾指针	
}LinkQueue;

	
//初始化队列函数
int initQueue(LinkQueue* Q){
	//给头尾结点分配内存,让队列中头尾指针指向同一个内存 
	Q->front  = (Qnode*)malloc(sizeof(Qnode));
	Q->rear = Q->front;
        //储存分配失败 
	if(!Q->front)return NO;
        //成功
	Q->front->next = NULL;
	return OK;
}

//插入元素,成为新的队尾元素
int insertQueue(LinkQueue* Q){

	
	Qnode* tempNode;//声明一个临时结点

	char *stuId = (char*)malloc(sizeof(12));//声明变量来接收输入
	
	tempNode = (Qnode*)malloc(sizeof(Qnode));
        //如果内存分配失败
	if(!tempNode)	return NO;

	//输入学号并保存			
	scanf("%s",stuId); 	
	tempNode->data = stuId;
	tempNode->next = NULL;
	Q->rear->next = tempNode;
	Q->rear = tempNode;		
	return OK;
}

//元素出队
char* outQueue(LinkQueue* Q){
	//若队列为空
	if(Q->front==Q->rear) {
		return NULL;  
	}
	//若队列不空,则让队列头部元素出队 
	Qnode* p = Q->front->next;
	char* data_return = p->data;
	Q->front->next = p->next; 
	//如果只有一个元素,该元素出队后,头尾指针都指向NULL。此时应该重置头尾指针指向,相当于重置链队列
	if(Q->rear==p) Q->rear = Q->front; 
	//如果不止一个元素,就不用重置尾指针位置 
	
	free(p);//回收内存
	return data_return;
} 

//销毁队列
int destroyQueue(LinkQueue* Q){
	while(Q->front){
		Q->rear = Q->front->next;
		free(Q->front);
		Q->front = Q->rear;
	}
	return OK;
}

//返回队列长度,用于计算还剩多少个元素结点在队列里
int queueLenth(LinkQueue* Q){
	Qnode* p =Q->front->next;
	int count=0;
	while(p){
		count++;
		p = p->next;
	}
	return count;
} 

//主函数
int main(){
	
	// 初始化队列 	
	LinkQueue Q;

	//定义一个表示选择的变量 
	int choice;
	
	//元素插入个数 
	int num; 
	
	//出队返回值
	char* back; 
	do{	
		printf("==========链队列操作===========\n");
		printf("1.初始化链队列\n");
		printf("2.元素入队\n");
		printf("3.元素出队\n");
		printf("4.销毁队列\n");
		printf("0.退出\n");
		printf("=====================\n");
		printf("请输入您的选择:");
		scanf("%d",&choice);
			switch(choice){
				case 1:
					initQueue(&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(!insertQueue(&Q))printf("------------\n-->> 第%d元素入队失败\n",i+1);
				} 
				
					break;
				case 3:
					back = outQueue(&Q);
					back? printf("------------\n 元素: %s 出队,还剩%d个元素\n",back,queueLenth(&Q)):printf("------------\n队列为空,无法出队!\n"); ; 			
					break;
				case 4:
					destroyQueue(&Q)?printf("------------\n队列销毁成功!\n"):printf("------------\n队列销毁失败!\n");
					break;
				case 0:
					printf("\n-->> 退出\n"); 
					exit(0);
					break;	
				default:
				 break; 
			}
	}while(choice);
	
	
}

 

主函数里主要是考虑到用户交互和视觉效果,所以有很多printf函数用来打分割符。

以上代码经过调试,我自认为没有问题(鄙人才疏学浅)。如果读者朋友们,有疑问和更正,欢迎评论区补充和探讨

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

落雨湿红尘

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

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

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

打赏作者

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

抵扣说明:

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

余额充值