5、队列的顺序存储结构:循环队列、两种方法
队列的ADT:
1 package ren.laughing.datastructure.base; 2 3 import ren.laughing.datastructure.exception.QueueEmptyException; 4 5 /** 6 * 队列Queue的ADT:先进先出 7 * 在队列中把插入数据元素的一端称为 队尾(rear), 删除数据元素 8 * 的一端称为 队首(front)。向队尾插入元素称为 进队或入队, 9 * 新元素入队后成为新的队尾元素;从队列中删除元素称为 离队或出队, 10 * 元素出队后,其后续元素成为新的队首元素。 11 * @author Laughing_Lz 12 * @time 2016年4月7日 13 */ 14 public interface Queue { 15 //返回队列的大小 16 public int getSize(); 17 //判断队列是否为空 18 public boolean isEmpty(); 19 //数据元素 e 入队 20 public void enqueue(Object e); 21 //队首元素出队 22 public Object dequeue() throws QueueEmptyException; 23 //取队首元素 24 public Object peek() throws QueueEmptyException; 25 }
循环队列的顺序存储实现,采用少一存储空间的方法:
1 package ren.laughing.datastructure.baseImpl; 2 3 import ren.laughing.datastructure.base.Queue; 4 import ren.laughing.datastructure.exception.QueueEmptyException; 5 /** 6 * 队列Queue的顺序存储,此处使用循环队列,逆时针,方法一 7 * ★循环队列:难点在于如何判断队空和队满 8 * 方法一:★少使用一个存储空间,即:当队尾指针的下一指针指向队首指针时,就停止入队。 9 * 判决:队空:rear=front,队满:(rear+1)%capacity = float 10 * 方法二:★增设一个标志size,以size?=MAX区别队满队空 11 * 判决:队空:size = 0,队满:size = capacity 12 * @author Laughing_Lz 13 * @time 2016年4月7日 14 */ 15 public class QueueArray implements Queue{ 16 private static final int CAP=7;//队列默认容量大小 17 private Object[] elements; 18 private int capacity;//数组的实际大小 elements.length 19 private int front; 20 private int rear; 21 22 public QueueArray() { 23 this(CAP); 24 } 25 public QueueArray(int cap) { 26 this.elements = new Object[capacity]; 27 this.capacity = cap+1;//这里数组实际大小capacity比队列容量cap大1 28 this.front = 0; 29 this.rear = 0; 30 } 31 //获取队列的容量 32 @Override 33 public int getSize() { 34 return (rear-front+capacity)%capacity;//返回队列的实际容量,小于等于capacity-1 35 } 36 //判断是否队空 37 @Override 38 public boolean isEmpty() { 39 if(rear == front){ 40 return true; 41 }else{ 42 return false; 43 } 44 } 45 //入队:相当于在insertAfter队尾 46 @Override 47 public void enqueue(Object e) { 48 // if(getSize()==capacity-1){//同下,判断队列容量是否已满 49 if((rear+1)%capacity == front){//判断是否队满 50 expandSpace();//扩充队列的容量 51 } 52 elements[rear] = e; 53 rear = (rear+1)%capacity;//rear有可能从capacity-1移动到0 54 } 55 //出队:相当于在remove队首 56 @Override 57 public Object dequeue() throws QueueEmptyException { 58 if(rear == front){//判断是否队空 59 throw new QueueEmptyException("错误:队列已空"); 60 } 61 Object obj = elements[front]; 62 elements[front] = null;//置空 63 front = (front+1)%capacity;//front有可能从capacity-1移动到0 64 return obj; 65 } 66 //获取队首数据元素 67 @Override 68 public Object peek() throws QueueEmptyException { 69 if(rear == front){//判断是否队空 70 throw new QueueEmptyException("错误:队列已空"); 71 } 72 return elements[front]; 73 } 74 /** 75 * ★扩充数组长度 76 */ 77 private void expandSpace() { 78 Object[] a = new Object[elements.length * 2]; 79 int i = front; 80 int j = 0; 81 while(i!=rear){//将从 front 开始到 rear 前一个存储单元的元素复制到新数组 82 a[j++] = elements[i]; 83 i = (i+1)%capacity; 84 } 85 elements = a; 86 capacity = elements.length; 87 front = 0; 88 rear = j;//重新设置新的队首队尾指针 89 } 90 }
循环队列的顺序存储实现,采用加标志size的方法:
1 package ren.laughing.datastructure.baseImpl; 2 3 import ren.laughing.datastructure.base.Queue; 4 import ren.laughing.datastructure.exception.QueueEmptyException; 5 /** 6 * 队列Queue的顺序存储,此处使用循环队列,逆时针,方法二 7 * ★循环队列:难点在于如何判断队空和队满 8 * 方法一:★少使用一个存储空间,即:当队尾指针的下一指针指向队首指针时,就停止入队。 9 * 判决:队空:rear=front,队满:(rear+1)%capacity = float 10 * 方法二:★增设一个标志size,以size?=MAX区别队满队空 11 * 判决:队空:size = 0,队满:size = capacity 12 * @author Laughing_Lz 13 * @time 2016年4月7日 14 */ 15 public class QueueArray2 implements Queue{ 16 private static final int CAP=8;//队列默认容量大小 17 private Object[] elements; 18 private int capacity;//数组的实际大小 elements.length 19 private int size;//队列容量(空/满判断标志) 20 private int front; 21 private int rear; 22 23 public QueueArray2() { 24 this(CAP); 25 } 26 27 public QueueArray2(int cap) { 28 this.elements = new Object[capacity]; 29 this.capacity = cap;//此处cap = capacity 30 this.size = 0;//队列初始为空 31 this.front = 0; 32 this.rear = 0; 33 } 34 //获取队列的容量 35 @Override 36 public int getSize() { 37 if(size == capacity){ 38 return capacity; 39 }else{ 40 return (rear-front+capacity)%capacity; 41 } 42 } 43 //判断是否队空 44 @Override 45 public boolean isEmpty() { 46 if(rear == front&&size !=capacity){ 47 return true; 48 }else{ 49 return false; 50 } 51 } 52 //入队:相当于在insertAfter队尾 53 @Override 54 public void enqueue(Object e) { 55 if(size == capacity){//判断是否队满 56 expandSpace();//扩充队列的容量 57 } 58 elements[rear] = e; 59 rear = (rear+1)%capacity;//rear有可能从capacity-1移动到0 60 size++; 61 } 62 //出队:相当于在remove队首 63 @Override 64 public Object dequeue() throws QueueEmptyException { 65 if(rear == front&&size != capacity){//判断是否队空 (此时size为0) 66 throw new QueueEmptyException("错误:队列已空"); 67 } 68 Object obj = elements[front]; 69 elements[front] = null;//置空 70 front = (front+1)%capacity;//front有可能从capacity-1移动到0 71 size--; 72 return obj; 73 } 74 //获取队首数据元素 75 @Override 76 public Object peek() throws QueueEmptyException { 77 if(rear == front&&size != capacity){//判断是否队空 (此时size为0) 78 throw new QueueEmptyException("错误:队列已空"); 79 } 80 return elements[front]; 81 } 82 /** 83 * ★扩充数组长度 84 */ 85 private void expandSpace() { 86 Object[] a = new Object[elements.length * 2]; 87 int i = front; 88 int j = 0; 89 do{//将从 front 开始到 rear 前一个存储单元的元素复制到新数组 90 a[j++] = elements[i]; 91 i = (i+1)%capacity; 92 }while(i!=rear);//★ 93 elements = a; 94 capacity = elements.length; 95 front = 0; 96 rear = j;//重新设置新的队首队尾指针 97 } 98 }
—————————————————————————————————————行走在人猿的并行线——Laughing_Lz