1. 程式人生 > >Java資料資料結構(三)——佇列

Java資料資料結構(三)——佇列

今天但看了大二資料結構這本書,對佇列進行一個整理。

文章目錄

一、什麼是佇列

佇列和棧一樣,都是一種受限制的線性表。佇列元素只能從隊尾插入(稱為入隊),隊首刪除(稱為出隊),就像排隊買奶茶,作為一名有素質的中國人,新來的人會自動地排在隊伍的後面,隊伍前面的人會先買到奶茶。這就是所謂的先進先出(First In First Out)。佇列實現的方式有兩種基本結構:陣列和連結串列。我們想要實現佇列的基本操作包括:

    //入隊
	//出隊
	//獲取隊首元素
	//獲取長度
	//是否為空
	//是否為滿
	//顯示佇列元素

二、順序陣列實現佇列

假設有這樣一個佇列,隊首處於陣列下標為0的位置,隊尾在陣列後端,那麼顯然入隊的時候就是在隊尾新增元素,時間複雜度為O(1),但是出隊的時候要刪除Array[0]的元素,陣列後面的元素需要全部往前移動,時間複雜度為O(n),顯然,如果把隊尾放在順序陣列的位置0處,那麼出隊的時間複雜度為O(1),入隊的時間複雜度為O(n),如圖所示:
在這裡插入圖片描述
針對上述的問題,我們可以新增兩個指標front(隊首),rear(隊尾),在入隊和出隊的操作只需要移動兩個指標的位置,而無需移動佇列中的元素,將時間複雜度都降為O(1)。
在這裡插入圖片描述
你以為這樣就完事了嗎?當然不是,陣列一個固有的特點,就是一旦建立之後陣列的大小就固定不變了,如果我們不斷地進行入隊和出隊操作,就會出現一系列問題,佇列滿了,陣列越界了!隨著front的值不斷增加,陣列前面的一大片空間就浪費了,記憶體是不是要哭死,哈哈!所以下面就會講述關於迴圈陣列實現佇列的方法來處理上述的弊端。

三、迴圈陣列實現佇列

使用網上優秀的圖,說明一下判斷佇列空和滿的方法。


在這裡插入圖片描述
程式碼實現:

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();
	}

測試結果:
在這裡插入圖片描述

四、連結串列實現佇列

利用連結串列實現佇列,可以動態地建立結點,不用預設大小,也不會造成空間的浪費,整個佇列的記憶體空間不連續,在實現插入和刪除操作更容易實現,但是存取速度會慢。鏈式佇列的實現就是對連結串列做了簡單的修改,根據佇列的特點,我們可以選用雙端連結串列的形式,建立兩個指標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());
	}
}

測試結果:
在這裡插入圖片描述