Java数据结构与算法2 队列

队列

  • 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

  • 队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表 (百度百科)

  • 队列分为顺序队列和循环队列,按实现方式又分为数组实现的队列和链表实现的队列。按数组实现,需要静态分配内存空间即指定该队列能存储多少个元素,具体来说,需要一个maxSize来控制队列的大小。对于数组模拟的队列,若不加以控制,会出现溢出和假溢出。在队列的形成过程中,也可以利用线性链表的原理,来生成一个队列。基于链表的队列,要动态创建和删除节点,效率较低,但是可以动态增长。因此,基于链表的队列理论上不会出现溢出现象。

数组实现的线性队列

通过数组来模拟线性队列,实现十分简单。我们新建一个类,包含以下属性和方法

属性/方法 解释
int arr[] 用于模拟队列的数组
int front 指向队头的索引,初始化为-1
int rear 指向队尾的索引,初始化为-1
int maxSize 队列最大存储的元素/对象个数
boolean isFull() 队列是否为满
boolean isEmpty() 队列是否为空
void add(int val) 入队一个元素val
int get() 出队一个元素
int peek() 查看一个元素但不出队
void show() 显示队列中的所有元素
  • 队满的判断条件:rear == maxSize-1
  • 队空的判断条件:rear == front
  • 入队:arr[++rear] = val
  • 出队:return arr[++front]

Java代码

package com.like.java.data_structure.queue;

/*
 *  通过数组来模拟顺序队列
 */
public class ArrayQueue {
	// 最大容量
	private int maxSize;
	private int front;
	private int rear;
	// 用于存放队列的数组
	private int[] arr;
	
	// 构造器
	public ArrayQueue(int maxSize)
	{
		this.maxSize = maxSize;
		// front指向队列头的前一个位置
		front = -1;
		rear = -1;
		arr = new int[maxSize];
	}
	
	// 判断队列是否为满
	public boolean isFull()
	{
		return rear == (maxSize-1);
	}
	
	// 判断队列是否为空
	public boolean isEmpty()
	{
		return front == rear;
	}
	
	// 入队
	public void add(int val)
	{
		if(isFull())
		{
			System.err.println("队列已满");
			return;
		}
		rear ++;
		arr[rear] = val;
	}
	
	// 出队
	public int get()
	{
		if(isEmpty())
		{
			// System.err.println("队列为空!");
			// 通过抛出异常来处理
			throw new RuntimeException("Empty Queue.");
		}
		
		front++;
		return arr[front];
	}
	
	// 遍历
	public void show()
	{
		// 判断是否为空
		if(isEmpty())
		{
			throw new RuntimeException("Empty Queue.");
		}
		for(int i=0;i<arr.length;i++)
		{
			System.out.printf("%d\t",arr[i]);
		}
		System.out.println();
	}
	
	// 显示队列头部
	public int peek()
	{
		if(isEmpty())
		{
			throw new RuntimeException("Empty Queue");
		}
		return arr[front+1];
	}
	
}

测试用例

package com.like.java.data_structure.queue;

import java.util.Scanner;

public class ArrayQueueTester {
	public static void main(String[] args) {
			// 创建一个队列对象
			ArrayQueue aqQueue = new ArrayQueue(3);
			Scanner scanner = new Scanner(System.in);
			
			char c = ' ';
			boolean loop = true;
			
			System.err.println("s(show queue)");
			System.err.println("a(add val)");
			System.err.println("e(exit)");
			System.err.println("g(get a val)");
			System.err.println("h(get header)");
			
			while(loop)
			{
				try {
					Thread.sleep(100);
				} catch (Exception e) {
					// TODO: handle exception
				}
				
				System.out.print("Command->");
				c = scanner.next().charAt(0);
				
				switch(c)
				{
				case 's':
					aqQueue.show();
					break;
				case 'a':
					System.out.print("Give a integet number:");
					int val = scanner.nextInt();
					aqQueue.add(val);
					break;
				case 'e':
					scanner.close();
					System.out.println("Exit 0");
					loop = false;
					System.exit(0);
				case 'g':
					try {
						int res = aqQueue.get();
						System.out.println("Get:"+res);
					} catch (Exception e) {
						// TODO: handle exception
						System.out.println(e.getMessage());
					}
					break;
				case 'h':
					try {
						int res = aqQueue.peek();
						System.out.println("Peek header:"+res);
					} catch (Exception e) {
						// TODO: handle exception
						System.out.println(e.getMessage());
					}
					break;
				default:
					System.out.println("Wrong command");
			}
		}
	}
}

数组实现循环队列

顺序队列不可避免的会出现假溢出现象,不能达到复用的效果。因此,我们需要引进循环队列这种改进的结构,用取模的方式来解决假溢出。

主要思想如下:

  1. 运用取模操作来进行判断队列为满的优化
  2. front指向当前队头元素,front = 0
  3. rear指向队尾元素的下一个位置,因为想空出一个空间作为约定,牺牲这个空间来判满,rear = 0.
  4. 满:(rear+1)%maxSize == front
  5. 空: rear == front
  6. 队列中有效元素的个数:(rear+maxSize-front)%maxSize / +maxSize来应对rear<front的情况

改进后的Java代码:

package com.like.java.data_structure.queue;
public class CircleArrayQueue {
	// 最大容量
	private int maxSize;
	private int front;
	private int rear;
	// 用于存放队列的数组
	private int[] arr;
	
	// 构造器
	public CircleArrayQueue(int maxSize)
	{
		this.maxSize = maxSize;
		// front指向队列头
		front = 0;
		rear = 0;
		arr = new int[maxSize];
	}
	
	// 判断队列是否为满
	public boolean isFull()
	{
		return (rear+1)%maxSize == front;
	}
	
	// 判断队列是否为空
	public boolean isEmpty()
	{
		return front == rear;
	}
	
	// 入队
	public void add(int val)
	{
		if(isFull())
		{
			System.err.println("队列已满");
			return;
		}
		arr[rear] = val;
		rear = (rear+1)%maxSize;
	}
	
	// 出队
	public int get()
	{
		if(isEmpty())
		{
			// System.err.println("队列为空!");
			// 通过抛出异常来处理
			throw new RuntimeException("Empty Queue.");
		}
		// 1. 先将front的值保存到一个临时变量
		// 2.front后移,考虑取模
		// 3. 将临时保存的变量保存
		int res = arr[front];
		front = (front+1)%maxSize;
		return res;
	}
	
	// 遍历
	public void show()
	{
		// 判断是否为空
		if(isEmpty())
		{
			throw new RuntimeException("Empty Queue.");
		}
		// 从front开始遍历(rear+maxSize-front)%maxSize个元素
		for(int i=front;i<front+size();i++)
		{
			System.out.printf("arr[%d] = %d\t",i%maxSize,arr[i%maxSize]);
		}
		System.out.println();
	}
	
	// 当前队列有效个数
	public int size()
	{
		return (rear+maxSize-front)%maxSize;
	}
	
	// 显示队列头部
	public int peek()
	{
		if(isEmpty())
		{
			throw new RuntimeException("Empty Queue");
		}
		return arr[front%maxSize];
	}
}

当然,在实际的项目中,我们可以使用java自带工具包中的队列来进行草所。java.util.Queue。
包含的主要方法:

方法 解释
offer(object x) /add(object x) 入队
poll()/remove() 出队
element()/peek() 查看第一个元素,不出队

Java代码- 可以参照以下示例
Java 实例 - 队列(Queue)用法

发布了80 篇原创文章 · 获赞 332 · 访问量 70万+

猜你喜欢

转载自blog.csdn.net/qq_40527086/article/details/104339713