[数据结构] 队列 (C语言)
队列
队列基本概念
队列( queue )是一种特殊的线性表结构,只从队尾插入新的元素,并且只从队首弹出元素。一般将队尾称为 rear,队首称为 front 。
队列基本操作
(1)入队:从队尾 rear 插入新元素;
(2)出队:从队首 front 弹出元素。
队列的特性
队列遵循 先进先出 的原则。比如元素 1、2、3、4、5 依次入队,且中途不存在出队过元素再次入队或其他元素入队,出队顺序为 1、2、3、4、5 。
循环顺序队列
循环顺序队列基本概念
顺序队列是用数组实现的队列,但是由于定义的数组的空间有限,可以想象一下,当队首 front 和 队尾 rear 经过一系列操作都往后移动时,之前所使用到的空间都不会再被使用了,这造成了空间上的浪费。
所以定义顺序队列往往采用更加高效的 循环顺序队列,其基本上就是在顺序队列的基础上加了一点小小的修改。
循环顺序队列的入队操作
循环顺序队列入队操作图解
初始状态下的循环顺序队列
元素1入队
元素2、3、4、5入队
循环顺序队列入队操作代码
//队列元素入队
void Enter_SqQueue(SqQueue *Q, int e){
if((Q->rear + 1) % MAXSIZE == Q->front){
printf("队列已满\n");
return;
}
Q->data[Q->rear] = e; //在队尾指向的地址赋值
Q->rear = (Q->rear + 1) % MAXSIZE; //队尾指针进1
}
循环顺序队列的出队操作
循环顺序队列出队操作图解
元素1出队
元素2、3、4、5出队
循环顺序队列出队操作代码
//队列元素出队
void Depart_SqQueue(SqQueue *Q, int *e){
if(IsEmpty(Q)){
printf("队列中无元素\n");
return;
}
*e = Q->data[Q->front]; //取出队首指针指向的地址元素
Q->front = (Q->front + 1) % MAXSIZE;//队首指针进1
}
循环顺序队列中的循环示例
入队
此时队列rear虽然指向数组的最后,但循环操作可以使其重复利用之前使用的空间。
出队
类似的此时队列front指向数组的最后
循环顺序队列完整程序
源代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 1000
typedef int Elemtype;
typedef struct SqQueue{
Elemtype data[MAXSIZE];
int front; //队列前指针
int rear; //队列后指针
}SqQueue;
//初始化
void Create_SqQueue(SqQueue *Q){
Q->front = Q->rear = 0;
}
//判断队列是否为空
bool IsEmpty(SqQueue *Q){
return Q->front == Q->rear;
}
//求得队列长度
int SqQueue_Length(SqQueue *Q){
return (Q->rear - Q->front + MAXSIZE) % MAXSIZE;
}
//队列元素入队
void Enter_SqQueue(SqQueue *Q, int e){
if((Q->rear + 1) % MAXSIZE == Q->front){
printf("队列已满\n");
return;
}
Q->data[Q->rear] = e; //在队尾指向的地址赋值
Q->rear = (Q->rear + 1) % MAXSIZE; //队尾指针进1
}
//队列元素出队
void Depart_SqQueue(SqQueue *Q, int *e){
if(IsEmpty(Q)){
printf("队列中无元素\n");
return;
}
*e = Q->data[Q->front]; //取出队首指针指向的地址元素
Q->front = (Q->front + 1) % MAXSIZE;//队首指针进1
}
//取队首
int Get_front(SqQueue *Q){
if(IsEmpty(Q)){
printf("队列为空\n");
return -1;
}
return Q->data[Q->front];
}
int main(){
SqQueue myQueue;
Elemtype a[5] = {35, 30, 11, 23, 9};
Create_SqQueue(&myQueue);
for(int i = 0; i < 5; i++)
Enter_SqQueue(&myQueue, a[i]);
Elemtype e;
Depart_SqQueue(&myQueue, &e);
printf("出队元素: %d\n", e);
printf("元素22入队并将所有元素出队: \n");
Enter_SqQueue(&myQueue, 22);
while(!IsEmpty(&myQueue)){
printf("%d ", Get_front(&myQueue));
Depart_SqQueue(&myQueue, &e);
}
return 0;
}
程序运行结果
链队列
链队列基本概念
链队列是链式的队列结构,其拥有一个 front 指针作为队首,一般队首 front 是不带数据的;还有一个 rear 指针作为队尾,队尾 rear 指向队列的最后一个元素。链队列的操作和链表也有一些相似之处。
链队列的入队操作
链队列入队操作图解
初始状态下的链队列
元素1入队
元素2、3入队
链队列入队操作代码
//链队列元素入队
void Enter_LinkQueue(LinkQueue *Q, int e){
Linknode *node = (Linknode*)malloc(sizeof(Linknode));
node->data = e;
node->next = NULL;
Q->rear->next = node; //原先队列尾指针后继next指向新节点node
Q->rear = node; //尾指针重新指向新节点node
}
链队列的出队操作
链队列出队操作图解
元素1出队
链队列出队操作代码
当链队列只有一个元素并且将其出队时,需要特判一下,将链队列置于空队列的状态。
//链队列元素出队
void Depart_LinkQueue(LinkQueue *Q, int *e){
if(Q->rear == Q->front) return;
Linknode *p;
p = Q->front->next; //要删除的节点暂存给p
*e = p->data; //取出删除队头节点的数据
Q->front->next = p->next; //队头节点的后继next直接跨过删除的节点指向其下一个节点
if(Q->rear == p) //当队列只有一个元素的情况
Q->rear = Q->front;
free(p);
}
链队列完整程序
源代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef int Elemtype;
//队列节点结构
typedef struct Linknode{
Elemtype data; //队列节点数据域
struct Linknode *next; //队列next指针域
}Linknode;
//链队列整体结构
typedef struct LinkQueue{
Linknode *front; //链队列首指针 队首指针不带数据
Linknode *rear; //链队列尾指针
}LinkQueue;
//初始化创建链队列
void Create_LinkQueue(LinkQueue *Q){
Q->front = Q->rear = (Linknode*)malloc(sizeof(Linknode));
Q->front->next == NULL;
}
//链队列元素入队
void Enter_LinkQueue(LinkQueue *Q, int e){
Linknode *node = (Linknode*)malloc(sizeof(Linknode));
node->data = e;
node->next = NULL;
Q->rear->next = node; //原先队列尾指针后继next指向新节点node
Q->rear = node; //尾指针重新指向新节点node
}
//链队列元素出队
void Depart_LinkQueue(LinkQueue *Q, int *e){
if(Q->rear == Q->front) return;
Linknode *p;
p = Q->front->next; //要删除的节点暂存给p
*e = p->data; //取出删除队头节点的数据
Q->front->next = p->next; //队头节点的后继next直接跨过删除的节点指向其下一个节点
if(Q->rear == p) //当队列只有一个元素的情况
Q->rear = Q->front;
free(p);
}
//判断是否为空
bool IsEmpty(LinkQueue *Q){
return Q->front == Q->rear;
}
//取队首
int Front_LinkQueue(LinkQueue *Q){
if(IsEmpty(Q)){
printf("队列为空\n");
return -1;
}
return Q->front->next->data;
}
int main(){
LinkQueue myQueue;
Create_LinkQueue(&myQueue);
Enter_LinkQueue(&myQueue, 1);
Enter_LinkQueue(&myQueue, 2);
Enter_LinkQueue(&myQueue, 3);
printf("当前队首元素为 %d \n", Front_LinkQueue(&myQueue));
Elemtype e;
Depart_LinkQueue(&myQueue, &e);
printf("出队的元素为 %d \n", e);
printf("当前队首元素为 %d \n", Front_LinkQueue(&myQueue));
printf("\n所有元素出队:\n");
while(!IsEmpty(&myQueue)){
printf("%d ", Front_LinkQueue(&myQueue));
Depart_LinkQueue(&myQueue, &e);
}
return 0;
}
程序运行结果
一切都是命运石之门的选择,本文章来源于博客园,作者:MarisaMagic,出处:https://www.cnblogs.com/MarisaMagic/p/17063234.html,未经允许严禁转载