什么是队列,队列的java数组实现

一、什么是队列?

队列是数据从表的一端进,另一端出,并遵循“先进先出” 原则的线性存储结构。

在这里插入图片描述图一(队列存储结构)
通常,称进数据的一端为 “队尾”,出数据的一端为 “队头”,数据元素进队列的过程称为 “入队”,出队列的过程称为 “出队”。
不仅如此,队列中数据的进出要遵循 “先进先出” 的原则,即最先进队列的数据元素,同样要最先出队列。拿图 1 中的队列来说,从数据在队列中的存储状态可以分析出,元素 1 最先进队,其次是元素 2,最后是元素 3。此时如果将元素 3 出队,根据队列 “先进先出” 的特点,元素 1 要先出队列,元素 2 再出队列,最后才轮到元素 3 出队列。

栈和队列不要混淆,栈结构是一端封口,特点是"先进后出";而队列的两端全是开口,特点是"先进先出"。

二、队列存储实现

队列存储结构的实现有以下两种方式:
1.顺序队列:在顺序表的基础上实现的队列结构;
2.链队列:在链表的基础上实现的队列结构;
(本文主要将顺序存储)

三、顺序队列简单实现

由于顺序队列的底层使用的是数组,因此需预先申请一块足够大的内存空间初始化顺序队列。除此之外,为了满足顺序队列中数据从队尾进,队头出且先进先出的要求,我们还需要定义两个指针(top 和 rear)分别用于指向顺序队列中的队头元素和队尾元素,如图 1 所示:
在这里插入图片描述图 1 顺序队列实现示意图

由于顺序队列初始状态没有存储任何元素,因此 top 指针和 rear 指针重合,且由于顺序队列底层实现靠的是数组,因此 top 和 rear 实际上是两个变量,它的值分别是队头元素和队尾元素所在数组位置的下标。
在图 1 的基础上,当有数据元素进队列时,对应的实现操作是将其存储在指针 rear 指向的数组位置,然后 rear+1;当需要队头元素出队时,仅需做 top+1 操作。
例如,在图 1 基础上将 {1,2,3,4} 用顺序队列存储的实现操作如图 2 所示:
在这里插入图片描述图二 数据进顺序队列的过程实现示意图

在图 2 基础上,顺序队列中数据出队列的实现过程如图 3 所示:

图三 数据出顺序队列的过程示意图

从以上我们可以大致知道,入队列时rear也就是队尾会向后移,出队列时top也就是队头向后移,当它们重合的时候,也就是队列元素为空的时候。

四、JAVA自带队列类的使用

public class Team {
    
    
	/*声明一个queue对象,
	    * ArrayBlockingQueue :一个由数组支持的有界队列。
	  * LinkedBlockingQueue :一个由链接节点支持的可选有界队列。
	  * PriorityBlockingQueue :一个由优先级堆支持的无界优先级队列。
	  * DelayQueue :一个由优先级堆支持的、基于时间的调度队列。
	  * SynchronousQueue :一个利用 BlockingQueue 接口的简单聚集(rendezvous)机制。*/
	Queue queue=new ArrayBlockingQueue(20);  
	public Team(){
    
    
		//入队
		queue.add(1);
		queue.add(2);
		queue.add(3);
		//出队
		queue.poll();
		System.out.println(queue);
	}
	public static void main(String[] args) {
    
    
		new Team();
	}
}

结果如图:
在这里插入图片描述
其中队列操作方法:
add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
  remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
  element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
  offer 添加一个元素并返回true 如果队列已满,则返回false
  poll 移除并返问队列头部的元素 如果队列为空,则返回null
  peek 返回队列头部的元素 如果队列为空,则返回null
  put 添加一个元素 如果队列满,则阻塞
  take 移除并返回队列头部的元素 如果队列为空,则阻塞
添加删除时尽量使用offer,poll,用add和remove失败抛异常

五、JAVA代码实现队列

package ddd;

public class Tesr {
    
    
	//因为如图中,队列刚开始指向0所以此处给它们两赋初值为0,正好也对应数组下标
	int rear=0;
	int top=0;
	//数组
	int arr[];
	//队列的长度
	int size;
	
	//给数组队列赋容量
		public void numArr(int num){
    
    
			this.size=num;
			arr=new int[num];
		}
		
	//判断队列是否为空
		public boolean isEmpty(){
    
    
			return rear==top;
		}
		
	//判断队列是否已满
		public boolean isFull(){
    
    
			return rear==size-1;
		}
		//入队
	public void add(int value){
    
    
		if(isFull()){
    
    
			throw new RuntimeException("队列已满");
		}
		rear++;
		arr[rear-1]=value;
		System.out.println("存入的值为:"+value);
	}
	//出队
	public void poll(){
    
    
		if(isEmpty()){
    
    
			throw new RuntimeException("队列已空");
		}
	 	top++;
	 	//top++之后指向下一个元素,取出的元素是++之前的元素,所以top-1
	 	System.out.println("取出的值为:"+arr[top-1]);
	}
	
	//遍历队列
	public void see(){
    
    
		if(isEmpty()){
    
    
			return ;
		}
		for (int i = 0; i <=rear-1; i++) {
    
    
			System.out.println(arr[i]);
		}
	}
	public static void main(String[] args) {
    
    
		Tesr test=new Tesr();
		test.numArr(20);
		test.add(1);
		test.add(2);
		test.add(3);
		test.poll();
		test.poll();
		test.poll();
		test.poll();
		test.see();
	}
}

测试结果如图:
在这里插入图片描述
以上是基于单向链表实现的,缺点在于:
指针 top 和 rear 重合位置指向了后续的重合点而不再是 a[0]。也就是说,整个顺序队列在数据不断地进队出队过程中,在顺序表中的位置不断后移。
顺序队列整体后移造成的影响是:

  • 顺序队列之前的数组存储空间将无法再被使用,造成了空间浪费;
  • 如果顺序表申请的空间不足够大,则直接造成程序中数组 a 溢出,产生溢出错误;

为了解决以上两个问题,可以使用巧妙的方法将顺序表打造成一个环状表,如下图所示:
在这里插入图片描述
只是一个想象图,在真正的实现时,没必要真创建这样一种结构,我们还是使用之前的顺序表,也还是使用之前的程序,只需要对其进行一点小小的改变:(具体改变下次更)
如有不足请指出

猜你喜欢

转载自blog.csdn.net/weixin_43909848/article/details/106410992