数组队列及循环队列

java数据结构之----数组队列及循环队列

数据结构与算法学习的第二篇

什么时候需要用到队列

队列在实际开发过程中运用的非常广泛,由于我也是学习基础,还没有开发过什么项目,所以用到时候就知道了

什么是队列

  • 队列是一个有序列表,可以用数组或者链表来实现
  • 队列遵守先入先出的原则

联系实际场景

可以把一个队列的存入,读取数据的过程看成在银行里面排队办理业务,进银行,取号,叫号,办理业务,出银行这几个过程。

具体图示

数组队列及循环队列_第1张图片

实现思路

由上面的图示,可以知道数组队列需要以下几个属性来完成模拟队列的实现:

基本属性

  • maxSize:表示队列的最大存储容量,也就是数组的大小
  • front:队头属性
  • rear:队尾属性
  • arrQueue:模拟队列的数组

实现过程

  1. 队列的输入和输出是由队头和队尾属性控制的,因此由front和rear分别记录下队列的前后端下标
  2. 当front 的下标志值等于rear的下标值时,队列为空
  3. 当rear 的值等于 maxSize - 1时队列为满队列
  4. 加入数据时队尾的rear增加1
  5. 输出出队时队列的front减少1

实现上述方法需要创建的方法

  • 判断队列是否是满队列的方法 isFull()
  • 判断队列是否为空队列的方法 isEmpty()
  • 增加数据的方法addQueue(),注意在增加数据时需要判断队列是否是满队列,是满队列的话数据增加不了
  • 获取队列数据的方法getQueue(),注意获取队列数据时需要判断队列是否为空队列,不然会产生错误
  • 显示队列中数据的方法 listQueue()
  • 获取队列队头数据的方法 getHead()

代码实现


		//测试队列  
		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):获取队列的头数据");
			System.out.println();
			
			key = scanner.next().charAt(0); //表示接收用户输入的数据
			switch (key) {
			case 's': //展示队列中的数据
				queue.listQueue();
				break;
			case 'e': //退出程序
				scanner.close();
				System.out.println("成功退出队列!");
				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);
					break;
				} catch (Exception e) {
					// TODO: handle exception
					System.out.println(e.getMessage());
				}
			case 'h': //显示队头数据
				try {
					int res = queue.headShow();
					System.out.printf("队头数据是:%d",res);
					System.out.println();
					break;
				} catch (Exception e) {
					// TODO: handle exception
					System.out.println(e.getMessage());
				}
			default:
				break;
			}
		}
		
		System.out.println("程序已退出");

	} 

}

/**
 * 1.使用数组模拟对列——编写一个 ArrayQueue 类
 */
class ArrayQueue{
	private int maxSize; //用于表示数组的最大容量
	private int front;  //队列的头指针
	private int rear;	//队列的尾指针
	private int []arrQueue; //用于存放数据的数组,模拟队列
	
	//用于创建对列的构造器
	public ArrayQueue(int n) {  //给各个属性初始化
		maxSize = n;
		front = -1; //队头指向数组第一个位置的前一个
		rear = -1;	//队尾指向数组的前一个位置
		arrQueue = new int[n]; //设置数组队列的大小
	}
	
	//判断队列是否满 
	//队列满的条件是 rear = maxSize -1; 因为数组的下标是从零开始的
	public boolean isFull() {
		return rear == maxSize -1;
	}
	
	//判断队列是否为空
	//队列为空的条件是 front == rear
	public boolean isEmpty() {
		return front == rear;
	}
	
	//增加数据到对列中
	public void addQueue(int n) {
		//增加数据时需要判断队列是否为满
		//为满的话,数据根本增加不进去
		if(isFull()) {
			System.out.println("队列是满的,无法加入数据");
			return;
		}
		
		rear++; //添加数据时移动的队尾指针
		arrQueue[rear] = n;
		System.out.println("数据添加成功");
	}
	
	//获取队列中的数据,也叫出队
	public int getQueue() {
		
		//获取队列的数据时需要判断队列的是否为空
		if(isEmpty()) {
			throw new RuntimeException("队列为空,无法获取");
		}
		
		front++;//数据出队时移动的是队头指针
		return arrQueue[front];
	}
	
	//显示队列中的数据
	public void listQueue() {
		
		//显示队列中的数据时需要先判断队列是否为空,为空则显示不了
		if(isEmpty()) {
			System.out.println("队列为空");
			return;
		}
		
		for(int i=0; i<=maxSize-1; i++) {
			System.out.printf("arr[%d] = %d", i,arrQueue[i]);
			System.out.println();
		}
	}
	
	//显示队列头数据
	public int headShow() {
		
		//显示队头数据也需要判断队列是否为空
		if(isEmpty()) {
			throw new RuntimeException("队列为空,无法显示");
		}
		
		return arrQueue[front+1];

这段代码实现后会发现,这个队列只能使用一次,当数组队列中的所有的位置都被使用过一次后,在将队列中的数据出队,新的数据无法添加到这个数组队列中,是因为,front和rear属性在执行方法时是单向移动,不能循环使用,所以当front移动到最后一个位置,rear也移动到最后一个位置后,虽然现实数组为空,但是添加不了数据,因为前面的空位rear去不了,后面又没有存储空间了,这就需要用到循环队列了。

差异代码展现

//判断是否为满
	public boolean isFull() {
		return (rear+1)%maxSize == front;
	}
	
	//添加数据
	public void addQueue(int n) {
		//增加数据时需要判断队列是否为满
		//为满的话,数据根本增加不进去
		if(isFull()) {
			System.out.println("队列是满的,无法加入数据");
			return;
		}
		
		//添加数据时不用再移动指向队尾的 rear
		arrQueue[rear] = n;
		//由于是循环队列所以 rear 可能会移动到数组的前面,
		//单纯的 ++ 操作无法实现要求,可能还会越界 
		rear = (rear + 1) % maxSize;
		System.out.println("数据添加成功");
	}

	//数据出队
	public int getQueue() {
		
		//获取队列的数据时需要判断队列的是否为空
		if(isEmpty()) {
			throw new RuntimeException("队列为空,无法获取");
		}
		
		//数据出队时就是 front 所指向的数组,不用后移动
		int value = arrQueue[front]; 
		front = (front + 1) % maxSize;
		return value;
	}

		//显示队列
	public void listQueue() {
		
		//显示队列中的数据时需要先判断队列是否为空,为空则显示不了
		if(isEmpty()) {
			System.out.println("队列为空");
			return;
		}
		
		//显示队列时不能仅仅以 数组大小来作为终止条件
		//需要知道 在队列数组中一共有多少个有效数据
		//借助 获取有效数据函数
		for(int i=front; i

循环数组队列和普通数组队列的不同处体现在这几个地方

  • 判断队列是否为满队列 (rear+1)%maxSize == front,通过这样可以计算 rear 移动到数组之前用过的位置的值
  • 添加数据时,通过下面的操作可以将 rear 移动到数组之前使用过的空间,重新来使用形成一个环。
	arrQueue[rear] = n;
 	rear = (rear + 1) % maxSize;
  • 需要添加一个方法,就是获取有效数据个数,
(rear+maxSize-front)%maxSize;

视频学习链接:https://www.bilibili.com/video/av54029771/?p=11

坚持者赢!!!

你可能感兴趣的:(数组队列及循环队列)