队列的认知和理解
队列(Queue)
队列简称队,它也是一种运算受限的线性表。队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。
与堆栈不同,如果说堆栈是几个人进入死胡同,后进的人先出,那么队列更像是几个人排队看电影,先排队的先进场去看。
1.队列的几个概念
- 把进行插入的一端称做队尾(rear)。
- 进行删除的一端称做队首或队头(front)。
- 向队列中插入新元素称为进队或入队,新元素进队后就成为新的队尾元素。
- 从队列中删除元素称为出队或离队,元素出队后,其后继元素就成为队首元素。
2.队列的基本运算和储存模式
- InitQueue(&q):初始化队列。构造一个空队列q。
- DestroyQueue(&q):销毁队列。释放队列q占用的存储空间。
- QueueEmpty(q):判断队列是否为空。若队列q为空,则返回真;否则返回假。
- enQueue(&q,e):进队列。将元素e进队作为队尾元素
- deQueue(&q,&e):出队列。从队列q中出队一个元素,并将其值赋
给e。
与堆栈相同,既然队列中元素逻辑关系与线性表的相同,队列可以采用与线性表相同的存储结构。
因为队列两端都在变化,所以需要两个指针来标识队列的状态。
3.队列的基本运算实现
队列的定义方法
typedef struct{
ElemType data[MaxSize];
int front,rear; //队首和队尾指针
} SqQueue;
还是假设MaxSize的数值为5
此时rear和front都指向-1,队列为空。
而后又进行了将一个a进队,bcde进队和全部出队的操作。
所以我们可以认为
- 约定rear总是指向队尾元素 。
- 元素进队,rear增1。
- 约定front指向当前队中队头元素的前一位置 。
- 元素出队,front增1。
- 当rear=MaxSize-1时不能再进队。
4.假溢出与环形队列
有这样一种情况:队列中明明还有位置却无法再对元素进行入队操作。如图
这是因为采用rear==MaxSize-1作为队满条件的缺陷。当队满条件为真时,队中可能还有若干空位置。
这种溢出并不是真正的溢出,称为假溢出。
而为了防止假溢出造成不必要的错误,我们可以使用一种环形队列:把数组的前端和后端连接起来,形成一个环形的顺序表,即把存储队列元素的表从逻辑上看成一个环,称为环形队列或循环队列。
那么对队列的操作将会变成:
那对于循环队列来说,循环队列的四要素就是:
- 队空条件:front = rear
- 队满条件:(rear+1)%MaxSize = front
- 进队e操作:rear=(rear+1)%MaxSize; 将e放在rear处
- 出队操作:front=(front+1)%MaxSize; 取出front处元素e;
但是我们要注意:
显然环形队列比非环形队列更有效利用内存空间,即环形队列会重复使用已经出队元素的空间。不会出现假溢出。
但如果算法中需要使用所有进队的元素来进一步求解,此时可以使用非环形队列。
以上为数据结构队列的一些认识。
参考资料:
- 武汉大学李春葆教授数据结构课件
- 百度百科
以上有错欢迎指正,希望让更多人看到。都看到这了点个赞再走呗☺