java数据结构与算法学习_队列与循环队列(数组实现)

队列(Queue)

队列是一个有序列表,可以用数组或是链表实现
遵循先入先出的原则,即先存入的数据先取出,后存入的数据后取出

数组模拟队列
队列本身是有序列表,若使用数组的结构来存储队列的数据,则将该数组称为队列数组

思路分析
maxSize是队列的最大容量,也就是数组的空间大小
front和rear都是数组的下标,用来记录队列的存入或取出的位置,即队列的头和尾

代码实现
(1)先定义一个队列类

class ArrayQueue{
	private int maxSize;//表示数组的最大容量
	private int rear;//队列尾,随着数据的存入而改变
	private int front;//队列头,随着数据的取出而改变
	private int[] arr;//该数组用于存放数据,模拟队列

	//构造方法,直接创建一个maxSize大小的数组存储数据
	public ArrayQueue(int maxSize) {
		this.maxSize = maxSize;
		this.arr = new int[maxSize];
		this.front = -1;//指向队列头部的前一个
		this.rear = -1;//指向队列的最后一个数据的具体位置
	}
}

(2)判断队列是否满或空

	//当队列满时,rear应该指向数组最后一个数据
	public boolean isFull() {
		return rear == maxSize - 1;
	}
	
	//当队列空时,front和rear相等
	public boolean isEmpty() {
		return rear == front;
	}

(3)添加数据
先判断队列是否满,如果满则添加失败
因为rear指向数组中最后一个数据,添加数据时应该先往后指一个位置,在该位置添加数据

	public boolean addQueue(int val) {
		//判断队列是否满
		if(this.isFull()) {
			System.out.println("队列已满,不能加入");
			return false;
		}
		else {
			this.rear++;
			arr[rear] = val;
			return true;
		}
	}

(4)取出数据
先判断队列是否空,如果空则取出数据失败
队列的数据取出从头部开始,即front指向的下一个数据,因此front先往后指一个位置,从该位置取出数据

public int getQueue() {
		if(this.isEmpty()) {
			//通过抛出异常处理
			throw new RuntimeException("队列为空,不能取数据");
		}
		else {
			this.front++;
			return arr[front];
		}
	}

(5)遍历数据
数组的遍历方法

	public void showQueue() {
		if(isEmpty()) {
			System.out.println("队列为空,无数据");
			return;
		}
		for(int i = this.front+1 ; i < arr.length ; i++) {
			System.out.printf("%d\n",arr[i]);
		}
	}

(6)显示头数据
注意不是取出

	public int headQueue() {
		if(isEmpty()) {
			throw new RuntimeException("队列为空,无数据");
		}
		
		else {
			return arr[front+1];
		}
	}

循环队列

因为数组队列会造成空间的浪费,因此使用循环队列来进一步优化

调整思路
1、front变量的含义做调整:front指向队列打的第一个元素,即arr[front]就是队列的第一个元素,初始值为0

2、rear变量的含义做调整:rear指向队列的最后一个元素的最后一个位置,因此队列需要空出一个位置,来作为队列是否满的标识,初始值为0

3、循环队列时,rear指向最后一个有效数据的下一个位置,因此判断队列是否满时,说明rear+1应该等于front:(rear+1) % maxSize == front

4、当队列为空时,rear == front

5、判断原始队列有效数据时,一般为rear-front,但循环队列时,可能会出现front > rear的情况,因此为保证结果为正数,判断循环队列有效数据为:(rear - front + maxSize) % maxSize

代码实现
(1)先定义一个队列类,成员变量不变,意义改变

	private int maxSize;//表示数组的最大容量
	private int rear;//队列尾:指向最后一个有效数据的下一个
	private int front;//队列头:指向第一个有效数据
	private int[] arr;//该数据用于存放数据,模拟队列
	
	//创建队列的构造器
	public CircleArray(int maxSize) {
		this.maxSize = maxSize;
		this.arr = new int[maxSize];
		this.front = 0;
		this.rear = 0;
	}
}

(2)判断队列是否满或空

	public boolean isFull() {
		return (this.rear + 1) % maxSize == front;
	}
	
	public boolean isEmpty() {
		return rear == front;
	}

(3)添加数据
rear意义改变,为最后一个有效数据的下一个位置,因此可以先添加在rear的位置,在 将rear向后移一个

	public boolean addQueue(int val) {
		//判断队列是否满
		if(this.isFull()) {
			System.out.println("队列已满,不能加入");
			return false;
		}
		else {
			arr[rear] = val;
			rear = (rear + 1) % maxSize;
			return true;
		}
	}

(4)取出数据
从front指向的位置取出

	public int getQueue() {
		if(this.isEmpty()) {
			//通过抛出异常处理
			throw new RuntimeException("队列为空,不能取数据");
		}
		else {
			//front指向队列的第一个元素
			//1 先把front对应的值保存到一个临时变量
			//2 将front后移
			int val = arr[front];
			front = (front + 1) % maxSize;
			return val;
		}
	}

(5)求当前队列有效数据个数及遍历队列

	public int size() {
		return (rear - front + maxSize) % maxSize;
	}
	
	//显示队列所有数据
	public void showQueue() {
		if(isEmpty()) {
			System.out.println("队列为空,无数据");
			return;
		}
		int count = size();
		for(int i = front ; i < front + count ; i++) {
			System.out.printf("%d\n",arr[i % maxSize]);
		}
	}

(6)显示头数据
注意不是取出

	public int headQueue() {
		if(isEmpty()) {
			throw new RuntimeException("队列为空,无数据");
		}
		
		else {
			return arr[front];
		}
	}

(7)测试类

public class CircleArrayQueue {
	public static void main(String[] args) {
		CircleArray arrayQueue = new CircleArray(4);
		char key = ' ';//接收用户输入
		Scanner scan = new Scanner(System.in);
		boolean loop = true;
		while(loop) {
			System.out.println("s(show):显示队列");
			System.out.println("e(exit):退出程序");
			System.out.println("a(add):添加数据到队列");
			System.out.println("g(get):从队列中取出数据");
			System.out.println("h(head):查看队列头的数据");
			key = scan.next().charAt(0);//接受一个字符串
			switch(key) {
				case 's':
					arrayQueue.showQueue();
					break;
				case 'e':
					scan.close();
					loop = false;
					break;
				case 'a':
					System.out.println("请输入添加的值");
					int val = scan.nextInt();
					arrayQueue.addQueue(val);
					break;
				case 'g':
					try {
					int temp = arrayQueue.getQueue();
					System.out.println("取出的值为" + temp);
					}catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
				case 'h':
					try {
						int res = arrayQueue.headQueue();
					    System.out.println("头数据为" + res);
					}catch(Exception e) {
						System.out.println(e.getMessage());	
					}
					break;
			}
		}
	}
}

循环队列关键点:脚标的改变以及对%的理解运用

你可能感兴趣的:(java数据结构与算法)