java数据结构与算法学习(三)
1.数组模拟循环队列
由上篇可知,如果我们直接用数组来模拟队列,那么在取出头部元素的时候,其头部元素仍然还是占着队列的内存的,无法再一次新添新元素进入该队列。
因此,我们这次来用数组来模拟一个循环的队列。
由图可知,循环队列的内存是可以灵活变动的。
注意:
maxSize: 队列的最大容量
front: 循环队列的头部,此时的front直接指向的是 该队列的第一个元素
rear: 队列的尾部, 此时的rear直接指向的是 该队列最后一个元素的下一位
元素入队的关键:
arr[rear] = n ;
rear = (rear + 1) % maxSize ;
元素出队的关键:
int value = arr[front] ; //先保存即将出队的元素,即队头元素
front = (front + 1) % maxSize ; //将front往后移动一位
return value ; //返回队头元素,此时循环队列已经没有了该元素的内存占用了
该循环队列的有效数值总数:
(rear + maxSize - front) % maxSize ; //因为是循环队列,因此其有效值的长度是尾部rear - 头部front + 最大值maxSize 然后取模maxSize的结果
}
package queue;
public class circleArrayQueue {
private int maxSize; //队列的最大容量
private int front; //头部,因为循环队列的front指的是队列的第一个元素,因此直接是front = 0
private int rear; //尾部,循环队列的rear指的是队列的最后一个元素的下一位
private int[] arr;
//构造器
public circleArrayQueue(int arrMaxSize) {
maxSize = arrMaxSize;
arr = new int[maxSize];
//front = 0; //此处无需定义front和rear的值
//rear = 0;
}
//判断队列是否为空
public boolean isEmpty() {
return rear == front;
}
//判断队列是否为满
public boolean isFull() {
return (rear + 1) % maxSize == front; //因为是循环队列,所以当rear的下一位的值等于front的话,将说明此队列已经满了
}
//入队
public void addQueue(int n) {
//判断是否为满
if (isFull()) {
System.out.println("此队列已满,无法入队!");
}
arr[rear] = n;
rear = (rear + 1) % maxSize;
}
//出队
public int outQueue() {
//判断是否队空
if (isEmpty()) {
throw new RuntimeException("此队列为空,无法出队!");
}
int value = arr[front]; //暂时保存队列的第一位元素
front = (front + 1) % maxSize; //front往后移动一位
return value; //成功返回队列的第一位元素
}
//获取队列的全部元素
public void showQueue() {
//判断是否队空
if (isEmpty()) {
System.out.println("此队列为空!");
}
//因为是循环队列,因此i直接等于front,然后遍历的范围是在front基础上的循环队列的有效长度,即front + size()
for (int i = front; i < front + size(); i++) {
System.out.printf("arr[%d] = %d\n",i % maxSize , arr[i % maxSize] );
}
}
//获取循环队列的有效值的总数
public int size() {
return (rear + maxSize - front) % maxSize; //因为是循环队列,因此其有效值的长度是尾部rear - 头部front + 最大值maxSize 然后取模maxSize的结果
}
//获取队列的头部元素
public int getHeadQueue() {
//判断队列是否为空
if(isEmpty()) {
throw new RuntimeException("此队列为空!");
}
return arr[front]; //由于循环队列的front直接指的是队列的第一位元素,因此直接输出即可
}
}
测试文件
package queue;
import java.util.Scanner;
import queue.*;
public class testCircleArrayQueue {
public static void main(String[] args) {
// 测试模拟队列的数组
//创建一个最大容量是4的队列
circleArrayQueue queue = new circleArrayQueue(4);
Scanner scanner = new Scanner(System.in);
char key = ' '; //用于接收用户的输入值
boolean loop = true; //用于while循环的状态表示
System.out.println("+++数组模拟循环队列的测试+++");
while(loop) {
//制作选项菜单
System.out.println("\n\n++++++++++++++++++++++++++++++++++++");
System.out.println("s(show) 显示该队列全部内容");
System.out.println("a(add) 添加元素进入队列");
System.out.println("o(out) 将队列头部元素出队");
System.out.println("g(get) 获取队列头元素");
System.out.println("e(exit) 退出");
System.out.println("++++++++++++++++++++++++++++++++++++");
System.out.println("请做出你的选择:");
key = scanner.next().charAt(0); //charAt(0)方法表示仅仅接收1个字符,防止用户输入的是数量>1的值
switch(key) {
case 's':
queue.showQueue();
break;
case 'a':
try {
System.out.println("请输入你要添加的元素:");
int n = scanner.nextInt();
queue.addQueue(n);
}catch(Exception e) {
System.out.println(e.getMessage());
}
break;
case 'o':
try {
int res = queue.outQueue();
System.out.printf("取出的元素是%d\t", res);
}catch(Exception e){
System.out.println(e.getMessage());
}
break;
case 'g':
try {
int res = queue.getHeadQueue();
System.out.printf("获取的队列头元素是%d\t", res);
}catch(Exception e) {
System.out.println(e.getMessage());
}
break;
case 'e':
loop = false;
break;
default:
break;
}
}
scanner.close(); //将scanner关闭
System.out.println("已退出!");
}
}
测试之后的结果:
- - 当队列未添加任何元素时,直接查看队列
- - 当队列先后添加11、22两个元素之后
- - 尝试取出头部元素时,已经成功取出了11
- - 再查看一下该队列的头部元素,它已经是22了
- - 然后查看整一个队列,发现此时只有arr[1]的22了,所以当arr[0]的11出队之后,其并未继续占用该队列的内存
- - 往循环队列插入新值33,再查看整一个队列的时候,发现arr[1]和arr[2]的值分别是22,33
- - 运行成功!
————————————————————————————————————————————
上一篇
java数据结构与算法学习(二)
java数据结构与算法学习(四)