我的算法日志:数据结构之顺序队列与循环队列
- 队列是一种操作受限制的线性结构,遵循“先进先出”原则,即遵循FIFO(First In First Out)原则。
- 换而言之,队列只允许在其前端(head)进行删除操作(出队),而在其后端(tail)进行插入操作(入队)。进行插入操作的端称为队尾,进行删除操作的端称为队头。
顺序队列
顺序队列是基于数组实现的, 即在连续存储单元中存放队列的元素,并设置head指示器指示队头,tail指示队尾。
每次在队尾插入一个元素是,tail增1(tail++);而每次在队头删除一个元素时,head增(head++)。随着插入和删除操作的进行,队列元素的个数不断变化,队列所占的存储空间也在为队列结构所分配的连续空间中移动。
但是这种设定容易出现“假溢出”现象:由于入队和出队操作中,头尾指示器只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于向量空间的规模时,也可能由于队尾指示器已超越向量空间的上界而不能做入队操作。
循环队列
解决“假溢出”的方法是将顺序队列改为首尾相接的循环结构,这种队列就是所谓的循环队列,又称顺序循环队列。
具体操作是:无论插入或删除,一旦队尾指示器tail增1或队头指示器head增1 时超出了所分配的队列空间(capacity),就让它指向这片连续空间的起始位置。
即队头指示器head增1的操作修改为:head = (head+1)%capacity
即队尾指示器tail增1的操作修改为:tail = (tail+1)%capacity
除此之外,我们还可以用一个变量size来记录队列的长度,然后通过size和capacity(容量)的组合来判断队列的状态。
Java代码实现循环队列:
1 package com.guohao.arithmetics; 2 3 import java.lang.reflect.Array; 4 5 /** 6 * 循环顺序队列 7 */ 8 public class SeqQueue<T> { 9 private T[] dataArray; //存放数据的数组 10 private int capacity; //队列的容量 11 private int size; //队列的长度 12 private int head; //队头元素的下标 13 private int tail; //队尾元素的下标 14 15 16 public SeqQueue(Class<T> type, int capacity){ 17 //为了保证类型安全,Java中不允许直接用泛型声明数组,如:"dataArray = new T[capacity]"是错误的! 18 dataArray = (T[]) Array.newInstance(type, capacity); 19 20 this.capacity = capacity; 21 size = 0; 22 head = 0; 23 tail = -1; 24 } 25 26 /** 27 * 入队 28 * @param element 29 * @return 30 */ 31 public boolean Enqueue(T element){ 32 if(!isFull()){ 33 tail = (tail+1)%capacity; 34 dataArray[tail] = element; 35 size++; 36 return true; 37 } 38 39 return false; 40 } 41 42 /** 43 * 出队 44 * @return 45 */ 46 public boolean Dequeue(){ 47 if(!isEmpty()){ 48 head = (head+1)%capacity; 49 size--; 50 } 51 52 return false; 53 } 54 55 /** 56 * 取队头元素 57 * @return 58 */ 59 public T peekHeadElement(){ 60 if(!isEmpty()){ 61 return dataArray[(head+1)%capacity]; 62 } 63 64 return null; 65 } 66 67 /** 68 * 判断是否满队 69 * @return 70 */ 71 public boolean isFull(){ 72 return size==capacity; 73 } 74 75 /** 76 * 判断是否空队 77 * @return 78 */ 79 public boolean isEmpty(){ 80 return size==0; 81 } 82 83 //getter & setter 84 public T[] getDataArray() { 85 return dataArray; 86 } 87 88 public void setDataArray(T[] dataArray) { 89 this.dataArray = dataArray; 90 } 91 92 public int getCapacity() { 93 return capacity; 94 } 95 96 public void setCapacity(int capacity) { 97 this.capacity = capacity; 98 } 99 100 public int getSize() { 101 return size; 102 } 103 104 public void setSize(int size) { 105 this.size = size; 106 } 107 108 public int getHead() { 109 return head; 110 } 111 112 public void setHead(int head) { 113 this.head = head; 114 } 115 116 public int getTail() { 117 return tail; 118 } 119 120 public void setTail(int tail) { 121 this.tail = tail; 122 } 123 124 125 }