我的算法日志:数据结构之顺序队列与循环队列

  • 队列是一种操作受限制的线性结构,遵循“先进先出”原则,即遵循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 }

 

posted @ 2020-04-23 08:15  凤青  阅读(443)  评论(0编辑  收藏  举报