Java数据结构之队列
队列的基本介绍
队列,是一个线性表,分为顺序队列和链式队列,本节我们说的是顺序队列。
队列存储在一段连续的存储空间之内(数组),它自身的特点是:先进先出,即从队尾添加元素,对头删除元素。
在平时的生活中,打印机等等用到的原理都是队列。
接下来我所讲的跟队列有关的内容分为两种:普通队列,循环队列。下面所有的代码都是可执行的(本人编写,亲测可用),写了一个小程序,用来实现队列的各种方法。
普通队列
示意图如下:
在这个队列中,我们暂定指向对头的指针为front,指向队尾的指针为rear,我们将front和rear的初始值都设置为-1,front会随着数据的输出而改变,rear也会随着数据的输入而改变。其次,在这个图中我们可以发现,我们需要给定一个数组的最大长度maxSize,并且显示一个数组。因此,我们可以得出的结论就是,在我们Java的构造函数中应该有4个元素:front,rear,maxSize,int[] arr;
关于普通队列的操作,由上图所示:
(1).当队列为空时:
front == rear;
(2).当队列为满时:
rear = maxSize-1;
(3).当添加队列元素时(假设添加的元素是n):
rear++;
arr[rear] = n;
(4).当删除队列元素时(这时,我们的程序需要返回删除的元素的值):
int value = 0; front++; value = arr[front];
(5).当遍历这个队列中的元素的时候,相应的,我们只需要遍历这个数组即可。
代码展示
在下面的代码中我会用注释说明,添加元素,删除元素等等的队列操作。(使用的编译器是Eclipse)
package queue; import java.util.Scanner; public class ArrayQueueDemo_1 { public static void main(String[] args) { ArrayQueued que = new ArrayQueued(4); Scanner sc = new Scanner(System.in); //用于用户的输入 char key = ' '; //标志变量 boolean flag = true; while(flag){ System.out.println("显示队列元素:s"); System.out.println("添加队列元素:a"); System.out.println("删除队列元素:d"); System.out.println("显示队头元素:h"); System.out.println("退出程序:e"); //charAt(0)相当于将字符串用字符返回 key = sc.next().charAt(0); switch(key){ case 'a': System.out.println("输入一个数字"); int value = sc.nextInt(); que.add(value); break; case 'd': int d = que.delete(); System.out.println(d); break; case 'h': que.head(); break; case 's': que.show(); break; case 'e': sc.close(); flag = false; break; default: break; } } System.out.println("程序结束"); } } //创建了一个队列的类,用来执行队列的各种操作 class ArrayQueued{ private int front; private int rear; private int[] arr; private int maxSize; //构造器,给指定的元素赋值 public ArrayQueued(int maxSize){ front = -1; //front的初始值是-1 rear = -1; //rear的初始值是-1 this.maxSize = maxSize; //maxSize的初始值由用户输入 arr = new int[maxSize]; //开辟maxSize大小的数组 } //判断队列是否为空 public boolean isEmpty(){ return front == rear; } //判断队列是否为满 public boolean isFull(){ return rear == maxSize - 1; } //向队列添加元素 public void add(int n){ try{ if(isFull()){ System.out.println("队列已经满,不能添加~"); return; } rear++; arr[rear] = n; }catch(Exception ex){ System.out.println(ex.getMessage()); } } //删除队列的元素 public int delete(){ if(isEmpty()){ System.out.println("队列为空,不能删除~"); } front++; int value = arr[front]; arr[front] = 0; //这个赋值是将删除元素的值全变成0 return value; } //显示队列中的元素 public void show(){ if(isEmpty()) System.out.println("队列为空,没有数据!"); for(int i=0;i<arr.length;i++){ System.out.printf("arr[%d] = %d\t",i,arr[i]); } System.out.println(); } //显示队列中的第一个元素 public void head(){ if(isEmpty()){ System.out.println("队列为空!"); } System.out.printf("对头元素:%d",arr[front+1]); System.out.println(); } }
循环队列
刚刚看完了普通队列,它虽然方便,但是有着很大的缺点,就是浪费内存空间(随着front,rear的增加,front下面的元素没法利用了),循环队列就是在普通队列的基础上进行了优化,让整个队列变成一个环,这样所有的空间都可以利用。
关于循环队列的表述:
(1).当队列为空时:
front == rear;
(2).当队列为满时:我们约定,尾索引的下一个元素为头索引时表示队列满,即:将队列容量空出一个作为约定
(rear+1)%maxSize == front;
(3).整个队列中元素的个数
(rear+maxSize-front)%maxSize
循环队列的表示跟普通队列有点不同,具体代码如下图所示
package queue; import java.util.Scanner; public class ArrayQueueCircle { public static void main(String[] args) { ArrayQueuec que = new ArrayQueuec(4); Scanner sc = new Scanner(System.in); //用于用户的输入 char key = ' '; //标志变量 boolean flag = true; while(flag){ System.out.println("显示队列元素:s"); System.out.println("添加队列元素:a"); System.out.println("删除队列元素:d"); System.out.println("显示队头元素:h"); System.out.println("退出程序:e"); //charAt(0)相当于将字符串用字符返回 key = sc.next().charAt(0); switch(key){ case 'a': System.out.println("输入一个数字"); int value = sc.nextInt(); que.add(value); break; case 'd': int d = que.delete(); System.out.println(d); break; case 'h': que.head(); break; case 's': que.show(); break; case 'e': sc.close(); flag = false; break; default: break; } } System.out.println("程序结束"); } } class ArrayQueuec{ private int front; private int rear; private int[] arr; private int maxSize; //构造器 public ArrayQueuec(int maxSize){ this.maxSize = maxSize; arr = new int[maxSize]; } //判断队列是否为空 public boolean isEmpty(){ return front == rear; } //判断队列是否为满 public boolean isFull(){ return (rear+1)%maxSize == front; } //队列长度 public int size(){ return (rear+maxSize-front)%maxSize; } //向队列添加元素 public void add(int n){ try{ if(isFull()){ System.out.println("队列已经满,不能添加~"); return; } arr[rear] = n; rear = (rear+1)%maxSize; }catch(Exception ex){ System.out.println(ex.getMessage()); } } //删除队列的元素 public int delete(){ if(isEmpty()){ System.out.println("队列为空,不能删除~"); } int value = arr[front]; front = (front+1)%maxSize; return value; } //显示队列中的元素 public void show(){ if(isEmpty()) System.out.println("队列为空,没有数据!"); for(int i=front;i<front+size();i++){ System.out.printf("arr[%d] = %d\t",i%maxSize,arr[i%maxSize]); } System.out.println(); } //显示队列中的第一个元素 public void head(){ if(isEmpty()){ System.out.println("队列为空!"); } System.out.printf("对头元素:%d",arr[front]); System.out.println(); } }
主要关注一下添加,删除还有遍历的不同~~~