橘生淮南

记录学习中的点点滴滴

0%

《数据结构》C语言版——链队列

队列:只允许在一端进行插入,在另一端进行删除的线性表

链队列:使用链表实现的队列,具有队头指针和队尾指针,指示队列元素所在的位置

链队列特性:
●只能队尾插入元素,在队头删除元素
●先进先出(First In First Out)的线性表,先进入的元素出队,后进入的元素才能出队

队列示意图:
在这里插入图片描述
空链队列:
在这里插入图片描述
链队的入栈操作:
在这里插入图片描述
链队的出栈操作:
在这里插入图片描述
————————纸上得来终觉浅,绝知此事要躬行————————

话不多说,把代码开起来,这样晦涩的概念才不会显得苍白无力!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include<stdio.h>
#include<malloc.h>
#include<assert.h>//断言

typedef int ElemType;//定义元素类型为int型

/*链队的结点类型*/
typedef struct QueueNode
{
ElemType data;
struct QueueNode *next;
}QueueNode,*PNode;

/*定义链队结构*/
typedef struct LinkQueue
{
PNode front;//队头指针指向头结点
PNode tail;//队尾指针
}LinkQueue;

/*初始化链队*/
void InitQueue(LinkQueue *Q)
{
//创建头结点
QueueNode *s=(QueueNode *)malloc(sizeof(QueueNode));
assert(s!=NULL);
Q->front=Q->tail=s;//队头指针和队尾指针都指向新结点
Q->tail->next=NULL;//队尾结点的指针域置空
}

/*入队*/
void EnQueue(LinkQueue *Q,ElemType x)
{
//队尾指针的next指向新创建的结点(新结点进行尾插)
//更改尾指针tail的指向
QueueNode *s=(QueueNode *)malloc(sizeof(QueueNode));
assert(s!=NULL);
s->data=x;
s->next=NULL;//新结点的指针域为空
Q->tail->next=s;//尾结点的指针域保存新结点的地址
Q->tail=s;//尾指针指向新结点
}

/*展示链队元素*/
void ShowQueue(LinkQueue *Q)
{
QueueNode *p=Q->front->next;//指针p指向头结点后第一个有效结点
printf("Front:>");
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next;//指针p指向下一个有效结点
}
printf("<:Tail\n");
}

/*出队*/
void DenQueue(LinkQueue *Q)
{
//出队相当于头部删除结点的过程:头结点的next指向第一个有效结点的后继,然后释放第一个有效结点
//注意:如果删除队尾结点,需要将队尾指针tail再次指向头结点
if(Q->front==Q->tail)//空队列
return;
QueueNode *p=Q->front->next;//指针p指向头结点后第一个有效结点
Q->front->next=p->next;//头结点的指针域保存第二个有效结点的地址
free(p);//释放第一个有效结点
if(p==Q->tail)//此时删除最后一个结点(尾结点)
Q->tail=Q->front;//队尾指针指向头结点
}

/*取链队头元素*/
void GetHead(LinkQueue *Q,ElemType *v)//用指针v带回链队头元素
{
if(Q->front==Q->tail)//空队列
return;
QueueNode *p=Q->front->next;//指针p指向头结点后第一个有效结点
*v=p->data;//p->data等价于Q->front->next->data
}

/*求链队长度*/
int Length(LinkQueue *Q)
{
int len=0;//初始化长度为0
QueueNode *p=Q->front->next;//指针p指向头结点后第一个有效结点
while(p!=NULL)//只有结点不为空,len增加
{
len++;
p=p->next;
}
return len;
}

/*清除链队*/
void ClearQueue(LinkQueue *Q)//除头结点外,对所有结点进行清除
{
if(Q->front==Q->tail)//如果头指针与尾指针指向相同,则链队为空
return;//无需清除
QueueNode *p=Q->front->next;//指针p指向头结点后第一个有效结点
while(p!=NULL)
{
Q->front->next=p->next;//头结点的指针域保存第二个有效结点的地址
free(p);//释放第一个有效结点
p=Q->front->next;//指针p重新指向头结点后第一个有效结点
}
//释放完成后,对尾部指针进行修改
Q->tail=Q->front;//队尾指针指向头结点
}

/*销毁链队*/
void DestroyQueue(LinkQueue *Q)//清除的前提下释放头结点实现销毁
{
ClearQueue(Q);
free(Q->front);//释放头结点
Q->front=Q->tail=NULL;//队头和队尾指针都赋空,预防野指针
}

void main()
{
LinkQueue Q;
ElemType e;//链队头元素
InitQueue(&Q);
for(int i=1;i<=10;++i)
{
EnQueue(&Q,i);
}
ShowQueue(&Q);
printf("出队\n");
DenQueue(&Q);
GetHead(&Q,&e);
printf("链队头元素为:%d\n",e);
ShowQueue(&Q);
printf("链队的长度为:%d\n",Length(&Q));
printf("\n");
printf("出队\n");
DenQueue(&Q);
GetHead(&Q,&e);
printf("链队头元素为:%d\n",e);
ShowQueue(&Q);
printf("链队的长度为:%d\n",Length(&Q));
printf("\n");
printf("出队\n");
DenQueue(&Q);
GetHead(&Q,&e);
printf("链队头元素为:%d\n",e);
ShowQueue(&Q);
printf("链队的长度为:%d\n",Length(&Q));
printf("\n");
printf("出队\n");
DenQueue(&Q);
GetHead(&Q,&e);
printf("链队头元素为:%d\n",e);
ShowQueue(&Q);
printf("链队的长度为:%d\n",Length(&Q));
printf("\n");
ClearQueue(&Q);
DestroyQueue(&Q);
}

运行结果:
在这里插入图片描述

欢迎关注我的其它发布渠道

-------------本文结束感谢您的阅读-------------