数据结构之队列的顺序存储
2014-05-19 22:25
288 查看
一、队列
队列是线性表的一种特殊形式,遵循“先进先出”的原则。队列中一般包含两个指针:一个指针(front)用来指向队首,另一个指针(rear)用来指向队尾。队列的操作如下图的a~i所示。上图中我们假设队列的最大长度为4。图a表示队列为空队,此时队首和队尾都是指向-1的;当元素A进队后(图b),队首不变,队尾指向元素A(下标为0);当元素B进队后(图c),队首不变,队尾指向元素B(下标为1);当元素C进队后(图d),队首不变,队尾指向元素C(下标为2);当元素D进队后(图e),队首不变,队尾指向元素D(下标为3),此时队列为满队,不允许再有元素入队了;当元素A出队时(图f),队首右移一个元素位置,队尾不变;以此类推,当元素D出队时(图i),队首右移一个元素位置,此时队首和队尾相遇了,表示队列为空。
总结:
1.队列是一种特殊的线性表,遵循“先进先出,后进后出”的原则,就跟我们在火车站排队买票一样;
2.队列为空时,front与rear指向同一位置;
3.队列为满队时,rear指向数组的最后一个元素;
4.采用普通的顺序存储队列时,队列存在“虚满”的情况,即rear指向数组的最后一个元素时,队列不一定是真正意义上的满队,有可能若干队首元素已经出队,如图f~h所示。为了防止“虚满”情况发生,可以采用以下两种方式:(1)队首元素出队后,将数组中的所有元素向前移动一格;(2)采用循环队列的方式。方式一的时间复杂度为O(n),方式二的时间复杂度为O(1),因此更多采用循环队列的方式来降低队列算法复杂度。
普通队列的实现代码如下所示。在队列类中,封装了队列构造、判断队列是否为空、判断队列是否为满队、入队、出队、获取队首元素等操作的方法。
public class Queue { private Object[] a; private int length = 100; private int front = -1; private int rear = -1; /** * 构造函数 */ public Queue() { a = new Object[length]; } /** * 重载构造函数 * * @param length 初始化队列的长度 */ public Queue(int length) { this.length = length; a = new Object[length]; } /** * 判断队列是否为空 * * @return 如果队列为空,返回true;否则,返回false */ public boolean isEmpty() { return front == rear; } /** * 判断队列是否为满队。该函数并不能真正判断队列是否已满,因为有可能一些元素已出队, * 因此在队首存在空缺。如果需要判断真正的队满,请参见循环队列中的判断队满函数。 * * @return 如果队列为满队,返回true;否则,返回false */ public boolean isFull() { return rear == length - 1; } /** * 获取队列中的元素,需要判断队列是否为空队 * * @return 如果队列为空,返回null;否则,返回队首元素 */ public Object get() { return isEmpty() ? null : a[front + 1]; } /** * 将队列中的队首元素出队,需要判断队列是否为空队 * * @return 如果队列为空,返回null;否则,返回队首元素 */ public Object outQueue() { return isEmpty() ? null : a[++front]; } /** * 向队尾添加元素item,需要判断队列是否为满队 * * @param item 向队尾中插入的元素 * @return 如果队满,返回false;否则,返回true */ public boolean inQueue(Object item) { if(isFull()) { return false; } else { a[++rear] = item; return true; } } }
二、循环队列
循环队列是队列的顺序存储结构的一种优化,主要是为了解决队列“虚满”的问题,提升队列空间的使用效率。循环队列采用存储结构同样是数组,只是将数组看成是一个环形结构而已。如下图所示。数组A[0...N]是一个具有N+1个元素的数组,我们假设该数组的头(0位置)和尾(N位置)是相接的。当队列中不存在任何元素时,队首(front)和队尾(rear)均指向数组下标为0的结点;当有元素A入队时,先将队尾(rear)右移一个位置至下标1,并将下标1位置写入元素A;当有元素出队时,先将队首(front)右移一个位置至下标1,并获取下标1位置的元素;当位置N处已经存在元素时,此时如果还有元素要入队,则判断数组下标为0的位置是否为队首,如果是,则表明队满了,如果不是,则将需要入队的元素写入下标0的位置。以此类推。
不难看出:循环队列的N+1个位置中,队首所指位置始终是不存在元素的,但不可否认,这一个位置的牺牲还是很有必要滴。
循环队列的实现代码如下。同样,代码中封装了判断队空、判断队满、入队、出队、获取队首元素等方法。
public class CycleQueue { private Object[] a; private int length = 100; private int front = 0; private int rear = 0; /** * 构造函数 */ public CycleQueue() { a = new Object[length]; } /** * 重载构造函数 * * @param length 初始化队列的长度 */ public CycleQueue(int length) { this.length = length; a = new Object[length]; } /** * 判断队列是否为空 * * @return 如果队列为空,返回true;否则,返回false */ public boolean isEmpty() { return front == rear; } /** * 判断队列是否为满队 * * @return 如果队列为满队,返回true;否则,返回false */ public boolean isFull() { return (rear + 1) % length == front; } /** * 获取队列中的元素,需要判断队列是否为空队 * * @return 如果队列为空,返回null;否则,返回队首元素 */ public Object get() { return isEmpty() ? null : a[(front + 1) % length]; } /** * 将队列中的队首元素出队,需要判断队列是否为空队 * * @return 如果队列为空,返回null;否则,返回队首元素 */ public Object outQueue() { if(isEmpty()) { return null; } else { front = (front + 1) % length; return a[front]; } } /** * 向队尾添加元素item,需要判断队列是否为满队 * * @param item 向队尾中插入的元素 * @return 如果队满,返回false;否则,返回true */ public boolean inQueue(Object item) { if(isFull()) { return false; } else { rear = (rear + 1) % length; a[rear] = item; return true; } } }
相关文章推荐
- 数据结构-队列的顺序存储(循环队列)
- 数据结构-队列-顺序存储完整可执行代码
- 数据结构---队列---循环队列---顺序存储
- 队列的顺序存储和链式表示方法-数据结构学习笔记2.3
- 数据结构学习笔记-队列的顺序存储(循环队列)
- 数据结构-队列-顺序链式存储
- 数据结构——队列之顺序存储
- 数据结构-循环队列顺序存储
- 数据结构学习之循环队列(顺序存储)
- 数据结构队列的顺序存储
- 数据结构示例之用数组顺序队列
- [置顶] 数据结构——循环队列存储结构以及实现
- 数据结构:线性表(顺序存储)顺序表类(实现顺序表的创建,输出,插入,删除功能)
- 数据结构例子-栈的顺序存储(利用数组)2
- 数据结构 链式-顺序存储
- 数据结构_线性表_顺序/链式存储优缺点比较
- 数据结构-栈的顺序存储
- 数据结构--串--定长顺序存储表示
- 队列的顺序存储
- 数据结构Java实现07----队列:顺序队列&顺序循环队列、链式队列、顺序优先队列