程序猿必修课之数据结构(八)队列

原文:http://www.jianshu.com/p/5d020c00fcb8

你还在为开发中频繁切换环境打包而烦恼吗?快来试试 Environment Switcher 吧!使用它可以在app运行时一键切换环境,而且还支持其他贴心小功能,有了它妈妈再也不用担心频繁环境切换了。https://github.com/CodeXiaoMai/EnvironmentSwitcher

上一章:程序猿必修课之数据结构(七)栈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 10
typedef 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);但是循环队列需要先申请好空间,使用期间不释放,而对于链队列,每次申请和释放结点也会存在一些时间开销。

从空间上来说,循环队列必须有一个固定的长度,这样就可能存在空间浪费的问题;而链队列不存在这个问题,尽管它需要一个指针域。

总的来说,在可以确定队列长度最大值的情况下,建议用循环队列,反之用链队列。

下一章:程序猿必修课之数据结构(九)串

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容