2-2 队列
2-2-1 队列的特点及抽象数据类型
队列(Queue)简称为队,也是一种受限的线性表,值允许在线性表的一端进行插入,而在表的另一端进行删除
称插入数据的一端为队尾(rear),称删除数据的一端为队首 (front).
向队列添加数据称为入队或进队,新入队的元素称为队尾元素,在队列中删除元素称为出队或离队,元素出队之后,它的后续元素称为新的队首元素.
队列是一种先进先出(First in First Out 简称 FIFO)
队列抽象数据类型的定义:
ADT Queue{
数据对象:D={a0,a1,a2...an,ai 都是同一数据类型的 元素}
数据关系:R={ai,ai+1}
数据操作:
getSize():返回元素个数
isEmpty():判断队列是否为空
enQueue(e):入队
deQueue():出队
peek():返回队首的元素
}ADT Queue
2-2-2 队列的顺序存储实现
在队列的实现中,可以把数组设想成一个圆环,这种数组称为循环数组,用循环数组晒西安的队列称为循环队列
用front指针指向 队首元素所在的单位,使用rear指针指向队尾元素所在的后一个单元
在元素入队时,将新入队的元素保存到rear指向的单元,然后rear指向后移;在出队时,将队首指针指向front指向的元素返回,然后front后移
一般情况下,我们用以下两种方式表示队列已满:
1.少用一个存储单元,当队尾指针rear指向下一个单元是队首指针front时,停止入队,(rear+1)%capacity==front时表示队列已满,当front==rear时表示队列为空
2.增设一个标志表示队列为空还是满,通常用size变量表示元素的个数,当size==0时队列为空,当size==capacity时表示队列已满.
1 package demo4.queue; 2 /** 3 * 队列的顺序存储实现 通过数组 4 * @author ASUS 5 * 6 */ 7 public class MyArrayQueue { 8 private Object[] elements; 9 private static final int DEFAULT_CAPACITY=8; 10 private int front; 11 private int rear; 12 private int size; 13 14 15 public MyArrayQueue(){ 16 elements =new Object[DEFAULT_CAPACITY]; 17 18 } 19 public MyArrayQueue(int initialCapacity){ 20 elements=new Object[initialCapacity]; 21 22 } 23 //返回元素的个数 24 public int getSize(){ 25 return size; 26 } 27 //判断队列是否为空 28 public boolean isEmpty(){ 29 return size==0; 30 } 31 //入队 32 public void enQueue(Object e){ 33 //如果队列已满,数组扩容 34 if(size>=elements.length){ 35 expandQueue(); 36 } 37 elements[rear]=e; //把元素存储到rear指向的单元 38 rear=(rear+1)%elements.length; //rear指针后移1 39 size++; 40 } 41 //对数组进行扩容 42 private void expandQueue() { 43 //定义更大的数组 44 Object[] newElements=new Object[elements.length*2]; 45 46 //把原来的内容复制到新数组,从队首开始依次复制到新数组索引0开始的位置 47 for(int i=0;i<elements.length;i++){ 48 newElements[i]=elements[front]; 49 front=(front+1%elements.length); 50 } 51 //把原来的数组名指向新的数组 52 elements=newElements; 53 //调整新的队首位置 54 front=0; 55 rear=size; 56 } 57 //出队 58 public Object deQueue(){ 59 //如果队列为空 60 if(size<=0){ 61 //抛异常 62 throw new QueueEmptyException("队列为空"); 63 } 64 //如果队列不为空,把front指向元素返回 65 Object old =elements[front]; 66 front=(front+1)%elements.length; 67 size--; 68 return old; 69 } 70 public Object peek(){ 71 //队列为空,跑异常 72 if(size<=0){ 73 throw new QueueEmptyException("队列为空"); 74 75 } 76 return elements[front]; 77 } 78 79 }
1 package demo4.queue; 2 /** 3 * 测试顺序存储的队列 4 * @author ASUS 5 * 6 */ 7 public class TestQueue { 8 9 public static void main(String[] args) { 10 System.out.println("测试顺序存储"); 11 MyArrayQueue queue=new MyArrayQueue(); 12 queue.enQueue("a"); 13 queue.enQueue("b"); 14 queue.enQueue("c"); 15 queue.enQueue("d"); 16 System.out.println(queue.getSize()); 17 System.out.println(queue.peek()); 18 System.out.println(queue.deQueue()); 19 20 } 21 22 }
运行截图:
1 package demo4.queue; 2 /** 3 * 自定义队列为空的异常 4 * 该异常为一个运行异常 5 * RuntimeException的子类就是运行异常 6 * @author ASUS 7 * 8 */ 9 public class QueueEmptyException extends RuntimeException{ 10 11 public QueueEmptyException() { 12 super(); 13 14 } 15 16 17 //String 参数,传递异常的信息 18 public QueueEmptyException(String message) { 19 super(message); 20 21 } 22 23 24 25 26 }
2-2-3 队列的链式存储
1 package demo4.queue; 2 3 /** 4 * 队列的链式存储 5 * @author ASUS 6 * 7 */ 8 public class MyLinkQueue { 9 private Node front; 10 private Node rear; 11 private int size; 12 13 //返回元素个数 14 public int getSize(){ 15 return size; 16 } 17 //判断队列是否为空 18 public boolean isEmpty(){ 19 return size==0; 20 } 21 //入队 22 public void enQueue(Object e){ 23 //根据添加的元素生成一个结点 24 Node newNode=new Node(e,null); 25 //把结点连接到队列中 26 if(rear==null){ 27 //这是添加的第一个元素,即是头结点也是尾结点 28 rear = newNode; 29 front=newNode; 30 }else{ 31 //把结点链拉到尾部 32 rear.next=newNode; 33 rear=newNode; //rear指针指向新添加的元素 34 } 35 size++; //元素个数加1 36 } 37 38 //出队 39 public Object deQueue(){ 40 //判断队列是否为空 41 if(size<=0){ 42 throw new QueueEmptyException("队列为空"); 43 } 44 Object old=front.elements; 45 front =front.next; 46 //如果出队后,队列为空,调整尾指针 47 if(front==null){ 48 rear=null; 49 } 50 size --; 51 return old; 52 } 53 //返回队首元素 54 public Object peek(){ 55 if(size<=0){ 56 throw new QueueEmptyException("队列为空"); 57 58 } 59 return front.elements; 60 } 61 //通过内部类表示单向链表的结点 62 private class Node{ 63 Object elements; 64 Node next; 65 public Node(Object elements, Node next) { 66 super(); 67 this.elements = elements; 68 this.next = next; 69 } 70 71 } 72 73 }
1 package demo4.queue; 2 /** 3 * 测试顺序存储的队列 4 * @author ASUS 5 * 6 */ 7 public class TestQueue { 8 9 public static void main(String[] args) { 10 11 12 System.out.println("测试链式存储"); 13 MyLinkQueue lqueue=new MyLinkQueue(); 14 lqueue.enQueue("aa"); 15 lqueue.enQueue("bb"); 16 lqueue.enQueue("cc"); 17 lqueue.enQueue("dd"); 18 lqueue.enQueue("ee"); 19 System.out.println(lqueue.getSize()); 20 //返回队首 21 System.out.println(lqueue.peek()); 22 System.out.println(lqueue.deQueue()); 23 System.out.println(lqueue.getSize()); 24 25 26 } 27 28 }
运行截图: