程序猿必修课之数据结构(八)队列
来源:互联网 发布:codewarrior软件 编辑:程序博客网 时间:2024/05/18 03:52
文本同步发布于简书:http://www.jianshu.com/p/5d020c00fcb8
上一章:程序猿必修课之数据结构(七)栈2
队列的定义
队列(Queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。
队列的抽象数据类型
队列是特殊的线性表,因此它的各种操作类似线性表,不同的是插入数据只能在队尾进行,删除数据只能在队头进行。
ADT 队列(Queue)Data 同线性表。元素的类型相同,相邻元素具有前驱和后继关系。Operation initQueue(*Q): 队列初始化,建立一个空队列。 destroyQueue(*Q): 若队列 Q 存在,就销毁它。 clearQueue(*Q): 将队列清空。 isEmpty(*Q): 若队列为空,返回 true;否则返回 false。 getHead(Q, *e): 若队列 Q 存在且不为空,则用 e 返回队列 Q 中的队头元素。 enQueue(*Q, e): 若队列 Que 存在,插入新元素 e 到队列 Q 中并成为队尾元素。 deQueue(*Q, *e): 删除队列 Q 中队头元素,并用 e 返回。 getLength(Q): 返回队列 Q 的元素个数。endADT
循环队列
我们把头尾相接的队列的顺序存储结构称为循环队列。
用 front 指针指向队头元素,用 rear 指针指向队尾元素的下一个位置(为了避免数组越界,队尾元素后要留一个空闲单元,保存 rear 指针)。所以当 front == rear 时,表示队列为空;当数组中只有一个空闲单元时队列就满了。
因为是循环队列,所以 rear 可能比 front 大,也可能比 fornt 小,如下图所示:
可以看出,它们可能只相差一个位置,但也可能相差整整一圈。所以若队列的最大容量为 queueSize,那么队列满的条件是:(rear + 1) % queueSize == front。
当 rear > front 时(即左图),队列的长度为 rear - front;当 rear < front 时(即右图),队列的长度由两部分构成,一部分是 queueSize - front,另一部分是 0 + rear,所以队列长度为 rear - front + queueSize。所以通用的计算队列长度的公式为:
(rear - front + QueueSize) % queueSize
循环队列的顺序存储结构
define MAXSIZE 10typedef struct { int data[MAXSIZE]; int front; int rear;} Queue;
初始化:
void initQueue(Queue *q) { q->front = 0; q->rear = 0;}
求队列长度
int queueLength(Queue q) { return (q->rear - q->front + MAXSIZE) % MAXSIZE;}
入队操作:
boolean enQueue(Queue *q, int e) { /* 队列已满 */ if ((q->rear + 1) % MAXSIZE == q->front) return false; q->data[q->rear] = e; q->rear = (q->rear + 1) % MAXSIZE; return true; }
出队操作:
boolean deQueue(Queue *q, int *e) { /* 队列为空 */ if (q->front == q->rear) return false; *e = q->data[q->front]; q->front = (q->front + 1) % MAXSIZE; return true;}
虽然循环队列解决了出队时算法的时间复杂度不高的问题,但是它仍然有数组可能会溢出的问题,所以还需要链式存储结构来解决这个问题。
队列的链式存储结构及实现
队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已,简称为链队列。
为了方便操作,队头指针指向链队列的头结点;尾指针指向终端结点。当 front 和 rear 都指向头结点时,队列为空。
链队列的结构为:
typedef struct QNode { int data; struct QNode *next;}QNode, *pQueue;typedef struct{ pQueue front; pQueue rear;}LinkQueue;
入队操作
boolean enQueue(LinkQueue *q, int e) { pQueue s = (pQueue)malloc(sizeof(QNode)); if(!s) return false; s->data = e; s->next = NULL; q->rear->next = s; q->rear = s; return true;}
出队操作
出队操作就是头结点的后继结点 p 出队,将头结点的后继改为 p 的后继结点,如果p 是 rear 指向的结点,那么还要将 rear 指向头结点。
boolean deQueue(LinkQueue *q, int *e) { pQueue p; if (q->front == q->rear) return false; p = q->front->next; *e = p->data; q->front->next = p->next; if(q->rear == p) q->rear = q->front; free(p); return true;}
比较循环队列和链队列
从时间复杂度,它们的基本操作都是 O(1);但是循环队列需要先申请好空间,使用期间不释放,而对于链队列,每次申请和释放结点也会存在一些时间开销。
从空间上来说,循环队列必须有一个固定的长度,这样就可能存在空间浪费的问题;而链队列不存在这个问题,尽管它需要一个指针域。
总的来说,在可以确定队列长度最大值的情况下,建议用循环队列,反之用链队列。
- 程序猿必修课之数据结构(八)队列
- 程序猿必修课之数据结构(三)线性表1
- 程序猿必修课之数据结构(四)线性表2
- 程序猿必修课之数据结构(五)线性表3
- 程序猿必修课之数据结构(六)栈1
- 程序猿必修课之数据结构(七)栈2
- 程序猿必修课之数据结构(一)数据结构基本概念和术语
- 程序猿必修课之数据结构(二)算法和算法的复杂度
- 数据结构(八) --- 队列
- 数据结构与算法之八 队列
- (八)抽象数据结构—队列
- 数据结构之顺序队列(循环队列)
- 数据结构(6)之队列
- 数据结构之队列(炫技篇)
- 数据结构之 (单向)队列
- 数据结构之队列(一)
- 数据结构之队列(二)
- 数据结构之队列(三)
- 第二章 React安装
- 谈一谈程序员写作
- Python中字典创建、遍历、添加等实用操作技巧合集
- springmvc上传文件
- 【语音识别】日语语音识别系统Julius(v4.4)的基于DNN的识别(5月8号:识别结果更新)
- 程序猿必修课之数据结构(八)队列
- C#.net 关键字之base老司机教学
- 创建模式->简单工厂模式-工厂方法模式-抽象工厂模式
- Qt creater5.5.1+win环境下加载vs2010编译的动态库
- Linux指令
- redo 和 undo log
- Android多语言项目的实现
- 自己写的String类,很基础!!!
- matplotlib简单使用