今天但看了大二数据结构这本书,对队列进行一个整理。


文章目录

  • 一、什么是队列
  • 二、顺序数组实现队列
  • 三、循环数组实现队列
  • 四、链表实现队列


一、什么是队列

队列和栈一样,都是一种受限制的线性表。队列元素只能从队尾插入(称为入队),队首删除(称为出队),就像排队买奶茶,作为一名有素质的中国人,新来的人会自动地排在队伍的后面,队伍前面的人会先买到奶茶。这就是所谓的先进先出(First In First Out)。队列实现的方式有两种基本结构:数组和链表。我们想要实现队列的基本操作包括:

//入队
	//出队
	//获取队首元素
	//获取长度
	//是否为空
	//是否为满
	//显示队列元素

二、顺序数组实现队列

假设有这样一个队列,队首处于数组下标为0的位置,队尾在数组后端,那么显然入队的时候就是在队尾添加元素,时间复杂度为O(1),但是出队的时候要删除Array[0]的元素,数组后面的元素需要全部往前移动,时间复杂度为O(n),显然,如果把队尾放在顺序数组的位置0处,那么出队的时间复杂度为O(1),入队的时间复杂度为O(n),如图所示:

JAVA 先进后出队列 java队列入队出队_System


针对上述的问题,我们可以添加两个指针front(队首),rear(队尾),在入队和出队的操作只需要移动两个指针的位置,而无需移动队列中的元素,将时间复杂度都降为O(1)。

JAVA 先进后出队列 java队列入队出队_JAVA 先进后出队列_02


你以为这样就完事了吗?当然不是,数组一个固有的特点,就是一旦创建之后数组的大小就固定不变了,如果我们不断地进行入队和出队操作,就会出现一系列问题,队列满了,数组越界了!随着front的值不断增加,数组前面的一大片空间就浪费了,内存是不是要哭死,哈哈!所以下面就会讲述关于循环数组实现队列的方法来处理上述的弊端。

三、循环数组实现队列

使用网上优秀的图,说明一下判断队列空和满的方法。

JAVA 先进后出队列 java队列入队出队_System_03


JAVA 先进后出队列 java队列入队出队_System_04


代码实现:

public CircleQueue() {
		maxSize = 4;
		front = 0;
		rear = 0;
		dataArr =(E[])new Object[maxSize];
	}
	//入队
	public void enqueue(Object data) {
		if(isFull()) {
			System.out.println("队列满了!!!");
		}else {
			dataArr[rear] = data;
			rear = (rear+1)%maxSize;
		}
	}
	//出队
	public Object dequeue() {
		if(isEmpty()) {
			System.out.println("队列空了!!!");
			return null;
		}else {
			Object o = dataArr[front];
			front = (front+1)%maxSize;
			return o;
		}
	}
	//获取队列长度
	public int length() {
		return (rear-front+maxSize)%maxSize;
	}
	//判断是否为空
	public boolean isEmpty() {
		return rear == front;
	}
	//判断是否为满
	public boolean isFull() {
		return (rear+1)%maxSize == front;
	}
	public void print() {
		if(length()==0) {
			System.out.println("队列元素为空");
		}else {
			System.out.println("队列元素为:");
			for(int i=front;i<=length();i++) {
				if(dataArr[i] != null) {
					System.out.println(dataArr[i]);		
				}
			}
		}
		System.out.println("rear="+rear);
		System.out.println("front="+front);
	}

测试代码:

public static void main(String[] args) {
		CircleQueue<Object> queue = new CircleQueue<>();
		queue.enqueue(2);
		queue.enqueue(3);
		queue.enqueue(4);
		System.out.println("队列长度=  "+queue.length());
		queue.print();
		queue.enqueue(5);
		System.out.println("队列长度=  "+queue.length());
		queue.print();
		queue.dequeue();
		queue.print();
	}

测试结果:

JAVA 先进后出队列 java队列入队出队_System_05

四、链表实现队列

利用链表实现队列,可以动态地创建结点,不用预设大小,也不会造成空间的浪费,整个队列的内存空间不连续,在实现插入和删除操作更容易实现,但是存取速度会慢。链式队列的实现就是对链表做了简单的修改,根据队列的特点,我们可以选用双端链表的形式,创建两个指针front,rear指向链表头结点和尾结点。
同样实现上述的基本操作。

package com.lm.MyQueue1121;

public class QueueLinklist {
	
	private Node front;
	private Node rear;
	public class Node{
		private Node next;
		private Object data;
		public Node(Object data) {
			this.data = data;
		}
	}
	public QueueLinklist() {
		front = null;
		rear = null;
	}
	
	//入队
	public void enqueue(Object value) {
			Node node = new Node(value);
			if(isEmpty()) {//注意插入第一个节点,要给front赋值
				rear = node;
				front = node;
			}else {
				rear.next = node;
				rear = node;	
			}
	}
	//出队
	public Object dequeue() {
		if(isEmpty()) {
			System.out.println("队列为空!!!");
			return null;
		}else {
			Object o = front.data;
			front = front.next;
			System.out.println(o+"  出队列");
			return o;
		}
	}
	//获取长度
	public int length() { 
		Node node = front;
		int len = 0;
		while(node != null) {
			len++;
			node = node.next;
		}
		return len;
	}
	//判断是否为空
	public boolean isEmpty() {
		return length()==0;
	}
	public void print() {
		Node node = front;
		if(node == null) {
			System.out.println("队列为空!!!");
		}
		while(node != null) {
			System.out.println("队列元素:"+node.data);
			node = node.next;
		}
	}
	public static void main(String[] args) {
		QueueLinklist queue = new QueueLinklist();
		queue.enqueue(1);
		queue.enqueue(2);
		queue.enqueue(3);
		queue.print();
		System.out.println("队列长度="+queue.length());
		queue.dequeue();
		queue.dequeue();
		queue.print();
		System.out.println("队列长度="+queue.length());
	}
}

测试结果:

JAVA 先进后出队列 java队列入队出队_JAVA 先进后出队列_06