我是靠谱客的博主 苗条裙子,这篇文章主要介绍六、队列,现在分享给大家,希望可以做个参考。

队列(Queue)是一种操作受限的线性表,它只允许在表的一端进行元素插入(入队),而在另一端进行元素删除(出队)。允许插入的一端称为队尾(rear),允许删除的一端称为队头(front)

队列示意图
从上面队列示意图可以看出队列具有先进先出的特性,因此又称队列为先进先出表(First In First Out,FIFO表)

一、顺序队列:队列的顺序存储结构称为顺序队列。

队列的顺序存储也是利用一块连续的存储单元存放队列中的元素,实际上是一个受限的线性表。因为队头和队尾的位置是变化的,因此需要设置两个指针front和rear表示队头和队尾在表中的位置。顺序队列的类型可以定义如下:

复制代码
1
2
3
4
5
6
7
8
#define QueueSize 100 typedef int DataType; typedef struct { DataType data[QueueSize]; int front, rear; }SeqQueue;

基本运算

复制代码
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
/* 初始化队列 */ void InitQueue(SeqQueue *q){ q->front = 0; q->rear = 0; } /* 入队 */ void EnQueue(SeqQueue *q,int x){ q->data[q->rear] = x; //入队时将新元素插入队尾rear的位置 q->rear = q->rear + 1; //在将队尾加1 } /* 出队 */ DataType DeQueue(SeqQueue *q){ DataType x = q->data[q->front]; //出队时记录删除的元素 q->front = q->front + 1; //将队头加1 } /* 空判断 */ int QueueEmpty(SeqQueue *q){ //当头尾指针相等时队列为空 return q->front == q->rear; }

下面是一个入队出队的操作例子:
入队出队示意图
当队列处于上图 (f) 状态时,如果再插入新元素就会产生上溢,而出队时空出的一些存储单元无法使用。如果队列的存储空间定义的太大,会产生存储空间的浪费。

为了充分利用数组空间,克服上溢,可将数据空间想象为一个环状空间,如下图:
循环队列示意图

二、循环队列:环状数组表示的队列

在循环队列中进行入队、出队时,头尾指针仍然需要加1,只不过当头尾指针指向数组上界(QueueSize - 1) 时,如果按正常加1运算,数组会产生越界溢出,因此需要判断加1后是否超过数组上届,若是则是其指向数组下届0。用i表示Q.front或Q.rear。则这种加1运算可描述为:

复制代码
1
2
3
4
5
if (i + 1 == QueueSize) // i 表示 Q.rear 或 Q.front i = 0; else i = i + 1;

利用求余(%)运算符将上述操作简化

复制代码
1
2
i = (i + 1) % QueueSize;

循环队列的顺序存储类型定义如下:

复制代码
1
2
3
4
5
6
7
8
9
#define QueueSize 10 typedef int DataType; typedef struct { DataType data[QueueSize]; int front, rear; }CirQueue;

基本方法如下:

复制代码
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
/* 初始化空队列 */ void InitQueue(CirQueue *q){ q->front = 0; q->rear = 0; } /* 判队空 */ int QueueEmpty(CirQueue *q){ //当头尾指针相等时队列为空 return q->front == q->rear; } /* 判队满 少用一个元素空间,约定入队前,测试尾指针在循环意义下加1是否等于头指针 若相等则队列满,即尾指针rear指向单元格始终为空(相当于尾指针占用一个空间) */ int QueueFull(CirQueue *Q){ return (Q->rear + 1) % QueueSize == Q->front; } /* 入队列 */ void EnQuque(CirQueue *Q,DataType x){ printf("添加x = %dn",x); if (QueueFull(Q)) { printf("队列已满n"); } else { Q->data[Q->rear] = x; Q->rear = (Q->rear+1) % QueueSize; //循环意义下的加1 } } /* 获取队头元素 */ DataType GetFront(CirQueue *Q){ if (QueueEmpty(Q)) { printf("队列为空n"); exit(0); } else{ return Q->data[Q->front]; } } /* 出队列 */ DataType DeQueue(CirQueue *Q){ DataType x; if (QueueEmpty(Q)) { printf("空队列n"); exit(0); } else { x = Q->data[Q->front]; //保存待删除的值 Q->front = (Q->front + 1) % QueueSize; //头指针加1 return x; } }

测试:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "stdio.h" #include "CirQueue.c" int main(){ CirQueue C,*Q; Q = &C; InitQueue(Q); for (int i = 2; i < QueueSize; i++) { EnQueue(Q,i); } int front = GetFront(Q); printf("入队之后头指针=%dn",front); DeQueue(Q); front = GetFront(Q); printf("出队之后头指针=%dn",front); return 0; }

运行结果:

复制代码
1
2
3
入队之后头指针=2 出队之后头指针=3

三、链队列

队列的链式存储结构称为链队列

链队列是一种限制在表头删除和表尾插入操作的单链表。为了方便入队和出队操作,一个链队列就由头指针和尾指针唯一确定。链队列的类型定义如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
typedef int DataType; typedef struct qnode{ DataType data; //数据域 struct qnode * next; //下个结点指针域 }QueueNode; //链队列结点类型 typedef struct{ QueueNode * front; //队头指针 QueueNode * rear; //队尾指针 }LinkQueue; //链队列类型

链队列一般也是不带头指针的,为了简化边界条件处理,在队头结点前附加一个头结点,并设头指针指向此结点。链队列结构示意图如下:
链队列结构示意图l链队列的基本运算:

复制代码
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
/* 初始化队列 */ void InitQueue(LinkQueue * Q){ Q->front = (QueueNode *)malloc(sizeof(QueueNode)); //申请头结点 Q->rear = Q->front; //队尾结点也指向头结点 Q->rear->next = NULL; } /* 队判空 */ int QueueEmpty(LinkQueue * Q){ return Q->front == Q->rear; //头尾指针相等,队列为空 } /* 入队列 */ void EnQueue(LinkQueue * Q, DataType x){ QueueNode * p = (QueueNode *)malloc(sizeof(QueueNode)); //申请新结点 p->data = x; p->next = NULL; Q->rear->next = p; //*p链到原队尾结点之后 Q->rear = p; //队尾指针指向新的的队尾指针 } /* 获取头元素 */ DataType GetFront(LinkQueue * Q){ if (QueueEmpty(Q)) { printf("空队列"); exit(0); } else { return Q->front->next->data; //返回队头元素 } } /* 出队列 */ DataType DeQueue(LinkQueue * Q){ QueueNode * p; if (QueueEmpty(Q)) { printf("空队列"); exit(0); } else { DataType x; p = Q->front; //p指向头结点 Q->front = Q->front->next; //头指针指向原队头结点 x = Q->front->data; free(p); //删除释放原头结点 return x; //返回被删除结点值 } }

测试:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main(){ LinkQueue Q; InitQueue(&Q); EnQueue(&Q,10); int front = GetFront(&Q); printf("头元素=%dn",front); EnQueue(&Q,100); DeQueue(&Q); front = GetFront(&Q); printf("头元素=%dn",front); return 0; }

运行结果:

复制代码
1
2
3
头元素=10 头元素=100

最后

以上就是苗条裙子最近收集整理的关于六、队列的全部内容,更多相关六、队列内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部