数据结构学习笔记——队列

来源:互联网 发布:python转义字符 编辑:程序博客网 时间:2024/06/05 19:55

队列的操作特性

先进先出,后进后出。

队列类型的实现

链队列——链式映像

typedef struct QNode {   QElemType data;   QNode *next; }*QueuePtr; struct LinkQueue {   QueuePtr front,rear; // 队头、队尾指针 };

循环队列——顺序映像

  • 用一组地址连续的存储单元依次存放从队头到队尾的元素。
  • 附设两个指针front和rear分别指示队头元素的位置和队尾元素的下一个位置。
  • 初始化建空队列时令front=rear=0,插入新的队尾元素时尾指针增加1,删除队头元素时头指针增加1。

普通的顺序队列会出现假上溢的情况。
因为在对队列的操作中,头尾指针只增加不减小,导致被删除元素的空间永远无法重新利用。尽管队列中实际的元素个数可能远远小于存储空间的规模,但仍不能做入队操作,该现象称为“假上溢”。
克服“假上溢”现象的方法是将顺序队列想象为一个首尾相接的圆环,称之为循环队列。

循环对列中无法通过Q.front=Q.rear来判断队列“空”还是“满”。解决此问题的方法至少有3种:
1. 另设一个标志位区别队列的“空”和“满”。
2. 使用一个计数器记录队列中元素的总数(也就是队列的长度)。
3. 少用一个元素的空间,约定以“队列头指针在队列尾指针的下一个位置(指环状的下一个位置)上”作为队列呈“满”状态的标志。
以下采用的是第3种方法。
循环队列的类型定义

#define MAXQSIZE 5 // 最大队列长度(对于循环队列,最大队列长度要减1) struct SqQueue {   QElemType *base; // 初始化的动态分配存储空间   int front; // 头指针,若队列不空,指向队列头元素   int rear; // 尾指针,若队列不空,指向队列尾元素的下一个位置 };

循环队列需要注意以下几点:

  1. 如果Q.front==Q.rear,则可以判断循环队列为空;
  2. 如果(Q.rear+1)%MAXQSIZE==Q.front,则可以判断循环队列为满。
  3. 无论是对循环队列进行插入或删除元素时,均可能涉及到尾指针或头指针的调整(非简单地对指针进行+1操作),即
    Q.rear=(Q.rear+1)%MAXQSIZE或Q.front=(Q.front+1)%MAXQSIZE
  4. 如何理解(Q.rear-Q.front+MAXQSIZE)%MAXQSIZE即为循环队列的长度

    1. 当Q.rear>Q.front时,循环队列长度=Q.rear-Q.front;
    2. Q.rear<Q.front时,循环队列长度=(Q.rear-Q.front+MAXQSIZE);
    3. 综合考虑以上两种情况,循环队列长度(任何情况下)=(Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;

队列与循环队列

关于循环队列是存储结构还是逻辑结构是有争议的,我更倾向于以下观点:
队列(包括循环队列)是一个逻辑概念,而链表是一个存储概念。一个队列是否是循环队列,不取决于它将采用何种存储结构,根据实际的需要,循环队列可以采用顺序存储结构,也可以采用链式存储结构,包括采用循环链表作为存储结构。

数据通过栈和队列产生的序列有什么不同?

  • 一串数据依次通过一个栈,并不能保证出栈的次序总是倒置的,可以产生多种出栈序列。
  • 一串数据通过一个栈后的次序由每个数据之间的入栈、出栈操作序列决定,只有当所有数据“全部入栈后再全部出栈”才能使数据倒置。事实上,存在一种操作序列——“入栈、出栈、入栈、出栈…”可以使数据通过栈后仍然保持次序不变。
    一串数据通过一个队列,只有一种出队列顺序,就是其入队列顺序。

几种特殊的队列:

  • 双端队列:可以在双端进行插入和删除操作的线性表。
  • 输入受限的双端队列:线性表的两端都可以输出数据元素,但是只能在一端输入数据元素。
  • 输出受限的双端队列:线性表的两端都可以输入数据元素,但是只能在一端输出数据元素。
0 0
原创粉丝点击