4.2 队列
4.2.1 队列的定义
队列简称队,它通栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。在队列中把插入数据元素的一端称为队尾(rear),删除元素的一端称为队首(front)。向队尾插入元素称为进队或入队。从队列中删除元素称为离队或出队。
队列是先进先出表(First In First Out,FIFO)。
队列的接口Queue:
1 package com.datastructure.chapter04.interfaces; 2 3 import com.datastructure.chapter04.Exception.QueueEmptyException; 4 5 /** 6 * @ClassName: Queue 7 * @Description: 队列的接口 8 * @author 9 * @date 2018年3月16日 下午10:09:17 10 * 11 */ 12 public interface Queue { 13 14 //返回队列打大小 15 public int getSize(); 16 17 //判断队列是否为空 18 public boolean isEmpty(); 19 20 //数据元素e入列 21 public void enqueue(Object e); 22 23 //队首元素出队 24 public Object dequeue() throws QueueEmptyException; 25 26 //取队首元素 27 public Object peek() throws QueueEmptyException; 28 }
队列为空的异常类:
1 package com.datastructure.chapter04.Exception; 2 3 @SuppressWarnings("serial") 4 public class QueueEmptyException extends RuntimeException { 5 6 public QueueEmptyException(String err) { 7 super(err); 8 } 9 }
4.2.2 队栈的顺序存储实现
1 package com.datastructure.chapter04.interfaces; 2 3 import javax.swing.tree.ExpandVetoException; 4 5 import com.datastructure.chapter04.Exception.QueueEmptyException; 6 7 public class QueueArray implements Queue { 8 9 private static final int CAP = 7;//队列默认大小 10 11 private Object[] elements;//数据元素数组 12 13 private int capacity;//数组的大小elements.length 14 15 private int front;//队首指针,指向队首 16 17 private int rear;//队尾指针,指向队尾后一个位置 18 19 public QueueArray() { 20 this(CAP); 21 } 22 23 public QueueArray(int cap) { 24 capacity = cap+1; 25 elements = new Object[capacity]; 26 front = rear = 0; 27 } 28 29 /* (非 Javadoc) 30 * <p>Title: getSize</p> 31 * <p>Description: 获得队列的长度</p> 32 * @return 33 * @see com.datastructure.chapter04.interfaces.Queue#getSize() 34 */ 35 @Override 36 public int getSize() { 37 return (rear-front+capacity)%capacity; 38 } 39 40 /* (非 Javadoc) 41 * <p>Title: isEmpty</p> 42 * <p>Description: 判断队列是否为空</p> 43 * @return 44 * @see com.datastructure.chapter04.interfaces.Queue#isEmpty() 45 */ 46 @Override 47 public boolean isEmpty() { 48 return front == rear; 49 } 50 51 /* (非 Javadoc) 52 * <p>Title: enqueue</p> 53 * <p>Description: 队列的入队</p> 54 * @param e 55 * @see com.datastructure.chapter04.interfaces.Queue#enqueue(java.lang.Object) 56 */ 57 @Override 58 public void enqueue(Object e) { 59 if(getSize()==capacity-1) expandSpace(); 60 elements[rear] = e; 61 rear = (rear+1)%capacity; 62 63 } 64 65 /** 66 * @Title: expandSpace 67 * @Description: 队列扩容 68 * @param 69 * @return void 70 * @throws 71 */ 72 private void expandSpace() { 73 Object[] a =new Object[elements.length*2]; 74 int i = front; int j=0; 75 76 while(i!=rear){ 77 a[j++] = elements[i]; 78 i = (i+1)%capacity; 79 } 80 elements = a; 81 82 capacity = elements.length; 83 front = 0; 84 rear = j;//设置新的队首,队尾指针 85 } 86 87 /* (非 Javadoc) 88 * <p>Title: dequeue</p> 89 * <p>Description: 队列的出队</p> 90 * @return 91 * @throws QueueEmptyException 92 * @see com.datastructure.chapter04.interfaces.Queue#dequeue() 93 */ 94 @Override 95 public Object dequeue() throws QueueEmptyException { 96 if(isEmpty()) 97 throw new QueueEmptyException("错误,队列为空"); 98 Object obj = elements[front]; 99 front = (front+1)%capacity; 100 return obj; 101 } 102 103 /* (非 Javadoc) 104 * <p>Title: peek</p> 105 * <p>Description: 获得队首元素</p> 106 * @return 107 * @throws QueueEmptyException 108 * @see com.datastructure.chapter04.interfaces.Queue#peek() 109 */ 110 @Override 111 public Object peek() throws QueueEmptyException { 112 if(isEmpty()) 113 throw new QueueEmptyException("错误,队列为空"); 114 return elements[front]; 115 } 116 117 }
以上有个循环数组的概念:就是将数组头和尾通过两个指针(front队首和rear队尾)来指向这两个位置,然后空队列,front=rear,满队列也是队尾和对首指向同一个位置。
顺序存储的队列时间复杂度T(n)=O(1);
4.2.3 队栈的链式存储实现
1 package com.datastructure.chapter04.impl; 2 3 import com.datastructure.chapter04.Exception.QueueEmptyException; 4 import com.datastructure.chapter04.interfaces.Queue; 5 6 public class QueueSLinked implements Queue { 7 8 private SLNode front; 9 10 private SLNode rear; 11 12 private int size; 13 14 public QueueSLinked() { 15 front = new SLNode(); 16 rear = front; 17 size = 0; 18 } 19 20 21 /* (非 Javadoc) 22 * <p>Title: getSize</p> 23 * <p>Description: 队列的长度</p> 24 * @return 25 * @see com.datastructure.chapter04.interfaces.Queue#getSize() 26 */ 27 @Override 28 public int getSize() { 29 return size; 30 } 31 32 /* (非 Javadoc) 33 * <p>Title: isEmpty</p> 34 * <p>Description: 队列是否为空</p> 35 * @return 36 * @see com.datastructure.chapter04.interfaces.Queue#isEmpty() 37 */ 38 @Override 39 public boolean isEmpty() { 40 return size == 0; 41 } 42 43 /* (非 Javadoc) 44 * <p>Title: enqueue</p> 45 * <p>Description: 入队</p> 46 * @param e 47 * @see com.datastructure.chapter04.interfaces.Queue#enqueue(java.lang.Object) 48 */ 49 @Override 50 public void enqueue(Object e) { 51 SLNode p = new SLNode(e, null);//创建新结点 52 rear.setNext(p);//队尾的下一个是新入队的结点 53 rear = p;//移动队尾指针至新入队的结点 54 size++;//长度加1 55 } 56 57 /* (非 Javadoc) 58 * <p>Title: dequeue</p> 59 * <p>Description: 出队</p> 60 * @return 61 * @throws QueueEmptyException 62 * @see com.datastructure.chapter04.interfaces.Queue#dequeue() 63 */ 64 @Override 65 public Object dequeue() throws QueueEmptyException { 66 if(size<=0) 67 throw new QueueEmptyException("错误:队列为空"); 68 SLNode p = front.getNext();//j 69 front.setNext(p.getNext());//直接将队首指向下下一个结点,就将队首结点移除掉了 70 size--; 71 if(size<1) rear = front;//若队列为空,rear指向头结点 72 return p.getData(); 73 } 74 75 /* (非 Javadoc) 76 * <p>Title: peek</p> 77 * <p>Description:取队首元素 </p> 78 * @return 79 * @throws QueueEmptyException 80 * @see com.datastructure.chapter04.interfaces.Queue#peek() 81 */ 82 @Override 83 public Object peek() throws QueueEmptyException { 84 if(size<=0) 85 throw new QueueEmptyException("错误:队列为空"); 86 return front.getNext().getData(); 87 } 88 89 }
链式存储队列时间复杂度T(n)=O(1);