内功之--队列

一.队列介绍

  • 有序列表,可以用数组和链表实现。
  • 先进先出。

二.数组模拟队列

1.队列是有序的,可以使用数组来模拟。MaxSize是数组的最大容量。

2.front和rear变量记录队列前后端的下标。front随着取出数据而变化,rear随着添加数据而变化。

3.当在队列中加入元素时:

 判断队列是否满:

满的条件:rear == MaxSize - 1

rear下标后移

当队列为空时

为空满足条件:rear =  = front;

rear++;

代码实现:

/** 
 * Project Name:leetcode 
 * File Name:ArrayQueue.java 
 * Package Name:queue 
 * Date:2020年2月3日上午8:49:31 
 * Copyright (c) 2020, [email protected] All Rights Reserved. 
 * 
*/

package queue;

import java.util.Scanner;

/**
 * ClassName:ArrayQueue <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date: 2020年2月3日 上午8:49:31 <br/>
 * 
 * @author yrz
 * @version
 * @see
 */
public class Queue {

	public static void main(String[] args) {
		// 创建一个队列
		ArrayQueue queue = new ArrayQueue(3);
		char key = ' '; // 接收用户输入
		Scanner scanner = 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 = scanner.next().charAt(0);// 接收一个字符
			switch (key) {
			case 's':
				queue.showQueue();
				break;
			case 'a':
				System.out.println("输出一个数");
				int value = scanner.nextInt();
				queue.addQueue(value);
				break;
			case 'g': // 取出数据
				try {
					int res = queue.getQueue();
					System.out.printf("取出的数据是%d\n", res);
				} catch (Exception e) {
					// TODO: handle exception
					System.out.println(e.getMessage());
				}
				break;
			case 'h': // 查看队列头的数据
				try {
					int res = queue.getQueueHead();
					System.out.printf("队列头的数据是%d\n", res);
				} catch (Exception e) {
					// TODO: handle exception
					System.out.println(e.getMessage());
				}
				break;
			case 'e': // 退出
				scanner.close();
				loop = false;
				break;
			default:
				break;
			}
		}

		System.out.println("程序退出~~");
	}

}

//用数组实现队列

class ArrayQueue {
	private int maxSize;// 队列最大容量
	private int front;// 对头指针
	private int rear;// 队尾指针
	private int[] arr;

	public ArrayQueue(int arrMaxSize) {
		maxSize = arrMaxSize;
		arr = new int[maxSize];
		front = -1;
		rear = -1;
	}

	// 判断队列是否为空
	public boolean isEmpty() {
		return front == rear;
	}

	// 判断队列是否已满
	public boolean isFull() {
		return rear == maxSize - 1;
	}

	// 添加队列元素
	public void addQueue(int data) {
		if (isFull()) {
			throw new RuntimeException("队列已满");
		}

		rear++;
		arr[rear] = data;
	}

	// 获取队列所有元素
	public void showQueue() {
		if (isEmpty()) {
			throw new RuntimeException("队列为空");
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.printf("arr[%d]=%d\n", i, arr[i]);
		}
	}

	// 取出队列头部元素
	public int getQueueHead() {
		if (isEmpty()) {
			throw new RuntimeException("队列为空");
		}
		return arr[front + 1];
	}

	// 获取队列元素
	public int getQueue() {
		if (isEmpty()) {
			throw new RuntimeException("队列为空");
		}
		front++;
		return arr[front];
	}
}

 三.存在问题及优化

      目前数组只能使用一次,不能够复用。

      原因:在getQueue方法中每取一个元素,front后移一位,数组元素出一位,这个位置会一直空着。

     优化:使用循环队列,要进行取模 %。

四.数组模拟循环队列

      分析:

  1. front:指向队列第一个元素。
  2. rear:指向队列最后一个元素后一个位置。
  3. 队列满的条件:(rear + 1)%maxsize == front。
rear maxsize   front  
1 5   0  
4 5 0 0
7 5 3 0  
         
  1. 队列为空的条件:rear = = front。
  2. 队列中有效元素的个数:(rear+ maxsize-front)%maxsize。
rear maxsize front maxsize  
3 5 1 5 2=3-1
8 5 1 5 2=8-5-1
  5 1 5  

          可以画图试试:取模对象是maxsize

     具体代码:

/** 
 * Project Name:leetcode 
 * File Name:CircleArrayQueue.java 
 * Package Name:queue 
 * Date:2020年2月3日下午3:23:53 
 * Copyright (c) 2020, [email protected] All Rights Reserved. 
 * 
*/

package queue;

import java.util.Scanner;

/**
 * ClassName:CircleArrayQueue <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date: 2020年2月3日 下午3:23:53 <br/>
 * 
 * @author yrz
 * @version
 * @see
 */
public class CircleArrayQueue {
	public static void main(String[] args) {
		// 创建一个队列
		CircleQueue queue = new CircleQueue(4);
		char key = ' '; // 接收用户输入
		Scanner scanner = 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 = scanner.next().charAt(0);// 接收一个字符
			switch (key) {
			case 's':
				queue.showQueue();
				break;
			case 'a':
				System.out.println("输出一个数");
				int value = scanner.nextInt();
				queue.addQueue(value);
				break;
			case 'g': // 取出数据
				try {
					int res = queue.getQueue();
					System.out.printf("取出的数据是%d\n", res);
				} catch (Exception e) {
					// TODO: handle exception
					System.out.println(e.getMessage());
				}
				break;
			case 'h': // 查看队列头的数据
				try {
					int res = queue.getQueueHead();
					System.out.printf("队列头的数据是%d\n", res);
				} catch (Exception e) {
					// TODO: handle exception
					System.out.println(e.getMessage());
				}
				break;
			case 'e': // 退出
				scanner.close();
				loop = false;
				break;
			default:
				break;
			}
		}

		System.out.println("程序退出~~");
	}
}

//数组实现环形队列
class CircleQueue {
	private int maxSize;// 队列最大容量
	private int front;// 指向队列的第一个元素,初始值为0
	private int rear;// 指向队列最后一个元素的后一个位置,初始值为0
	private int[] arr;

	public CircleQueue(int arrMaxSize) {
		maxSize = arrMaxSize;
		arr = new int[maxSize];
	}

	// 判断环形队列是否为空
	public boolean isEmpty() {
		return front == rear;
	}

	// 判断环形队列是否已满
	public boolean isFull() {
		return (rear + 1) % maxSize == front;
	}

	// 添加环形队列元素
	public void addQueue(int data) {
		if (isFull()) {
			System.out.println("队列已满");
			return;
		}

		// 先添加元素
		arr[rear] = data;
		// 再往后移一位
		// rear++;

		// 这里指针要取模
		rear = (rear + 1) % maxSize;
	}

	// 获取环形队列所有元素
	public void showQueue() {
		if (isEmpty()) {
			System.out.println("队列为空");
			return;
		}

//		for (int i = front; i < size() + 1; i++) {
//			System.out.printf("arr[%d]=%d\n", i, arr[i]);
//		}

//		for (int i = front; i < size() + front; i++) {
//			System.out.printf("arr[%d]=%d\n", i, arr[i]);
//		}
		for (int i = front; i < size() + front; i++) {
			System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
		}
	}

	// 获取环形队列有效元素个数
	public int size() {
		return (rear + maxSize - front) % maxSize;
	}

	// 取出队列头部元素
	public int getQueueHead() {
		if (isEmpty()) {
			throw new RuntimeException("队列为空");
		}
		return arr[front];
	}

	// 获取队列元素
	public int getQueue() {
		if (isEmpty()) {
			throw new RuntimeException("队列为空");
		}

		// 用临时变量value记录front位置元素值
		int value = arr[front];
		// front 后移
		// front++;

		// front 后移取模
		front = (front + 1) % maxSize;
		// 返回value
		return value;
	}
}

运行结果:

s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
s
队列为空
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
a
输出一个数
10
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
s
arr[0]=10
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
a
输出一个数
20
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
s
arr[0]=10
arr[1]=20
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
a
输出一个数
30
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
s
arr[0]=10
arr[1]=20
arr[2]=30
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
a
输出一个数
40
队列已满
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
s
arr[0]=10
arr[1]=20
arr[2]=30
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
g
取出的数据是10
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
s
arr[1]=20
arr[2]=30
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
a
输出一个数
50
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
s
arr[1]=20
arr[2]=30
arr[3]=50
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
h
队列头的数据是20
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据
s
arr[1]=20
arr[2]=30
arr[3]=50
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据

      

发布了51 篇原创文章 · 获赞 20 · 访问量 8015

猜你喜欢

转载自blog.csdn.net/yuruizai110/article/details/104163841