【資料結構】佇列(順序佇列、鏈佇列)的JAVA程式碼實現

Yngz_Miao發表於2018-03-28

佇列(queue)是一種特殊的線性表,只允許在表的一端進行插入操作而在另一端進行刪除的線性表。進行插入操作的端稱為隊尾,進行刪除操作的一端稱為隊頭。佇列中沒有資料元素時稱為空佇列。

佇列的操作是按照先進先出(first in first out)或後進後出(last in last out)的原則進行的。因此,佇列又被稱為FIFO表。它的實現方式主要有順序佇列、鏈佇列兩種

 

佇列的抽象資料模型

  1. 資料元素:可以為任意型別,只要同屬於一種資料型別即可;
  2. 資料關係:資料元素之間呈線性關係;
  3. 資料操作:對佇列的基本操作定義在IQueue中,程式碼如下:
public interface IQueue<E> {
	boolean enqueue(E item); //入佇列操作
    E dequeue(); //出佇列操作
    E peek(); //取對頭元素
    int size(); //求佇列的長度
    boolean isEmpty(); //判斷佇列是否為空  
    boolean isFull(); //判斷佇列是否為滿  
}

佇列的實現方式

順序佇列

用一片連續的儲存空間來儲存佇列中的資料元素,這樣的佇列稱為順序佇列。類似於順序棧,用一維陣列來存放順序佇列中的資料元素。隊頭設定在最近一個已經離開佇列的元素所佔的位置,用front表示;隊尾設定在最近一個進行入佇列的元素位置,用rear表示。front和rear隨著插入和刪除而變化。當佇列為空時,front=rear=-1。

當有資料元素入佇列時,隊尾指示器rear加1,當有資料元素出佇列時,隊頭指示器front加1。當front=rear時,表示佇列為空,當隊尾指示器rear達到陣列的上限處而front為-1時,佇列為滿。隊尾指示器rear的值大於對頭指示器front的值,佇列中的元素個數可以由rear-front求得。

但是!有時候,佇列未滿但再有一個元素入隊就會出現溢位。但事實上佇列並未滿,還有空閒空間,這種情況成為“假溢位”。這是由於佇列“隊尾入隊,隊頭出”的操作原則造成的。解決假溢位的方法是將順序佇列看成是首尾相接的迴圈結構,首尾指示器的關係不變,這種佇列叫迴圈順序佇列。

當隊尾指示器rear達到陣列的上限是,如果還有資料元素入隊並且陣列的第0個空間空閒時,隊尾指示器rear指向陣列的0端。所以,隊尾指示器的加1操作修改為:rear=(rear+1)%maxsize

隊頭指示器的操作也是如此。當隊頭指示器front達到陣列的上限時,如果還有資料元素出隊,隊頭指示器指向陣列的0端。所以,隊頭指示器的加1操作修改為:front=(front+1)%maxsize

這樣又有一個問題,隊滿和隊空的時候,都有rear=front。為了解決這個問題的方法是一般少用一個空間,所以判斷隊空的條件是rear=front,判斷隊滿的條件是(rear+1)%maxsize=front,與此同時,迴圈佇列中資料元素的個數是(rear-front+maxsize)%maxsize。此時,front表示隊頭,rear表示隊尾,兩者的範圍都是0-maxsize-1。

public class SeqQueue<E> implements IQueue<E> {
	private int maxsize; //佇列的容量
	private E[] data; // 儲存迴圈順序佇列中的資料元素
	private int front; // 指示最近一個己經離開佇列的元素所佔的位置
	private int rear; // 指示最近一個進行入佇列的元素的位置
    //初始化佇列
	@SuppressWarnings("unchecked")
	public SeqQueue(Class<E> type, int maxsize) {
		data = (E[]) Array.newInstance(type, maxsize);
		this.maxsize = maxsize;
		front = rear = -1;
	}
	//入佇列操作
	public boolean enqueue(E item) {
		if (!isFull()) {
			rear = (rear + 1) % maxsize;
			data[rear] = item;
			return true;
		} else
			return false;
	}
	 //出佇列操作
	public E dequeue() {
		if (!isEmpty()) {
			front = (front + 1) % maxsize;
			return data[front];
		} else
			return null;

	}
	
	//取對頭元素
	public E peek() {
		if (!isEmpty()) {
			return data[(front + 1) % maxsize];
		} else
			return null;
	}
	//求佇列的長度
	public int size() {

		return (rear - front + maxsize) % maxsize;
	}
	// 判斷佇列是否為空
	public boolean isEmpty() {
		if (front == rear) {
			return true;
		} else {
			return false;
		}
	}
	// 判斷迴圈順序佇列是否為滿
	public boolean isFull() {
		if ((front == -1 && rear == maxsize - 1)
				|| (rear + 1) % maxsize == front) {
			return true;
		} else {
			return false;
		}
	}
}

鏈佇列

用鏈式儲存結構來儲存佇列中的資料元素,這樣的佇列稱為鏈佇列。同鏈棧一樣,鏈佇列一般也採用單連結串列來表示,設隊頭指示器為front,隊尾指示器rear。

class QueueNode<E>
{
	private E data; // 資料域
	private QueueNode<E> next; // 引用域
	 //建構函式
	public QueueNode(){}
	public QueueNode(E data) {
		this.data = data;	
	}
	public QueueNode(E data, QueueNode<E> next) {
		this.data = data;
		this.next = next;
	}
	//資料域get屬性
	public E getData() {
		return data;
	}
	//資料域set屬性
	public void setData(E data) {
		this.data = data;
	}
	//引用域get屬性
	public QueueNode<E> getNext() {
		return next;
	}
	//引用域get屬性
	public void setNext(QueueNode<E> next) {
		this.next = next;
	}
}
public class LinkQueue<E> implements IQueue<E> {
	private QueueNode<E> front; // 佇列頭指示器
	private QueueNode<E> rear; // 佇列尾指示器
	private int maxsize; // 佇列的容量,假如為0,不限容量
	private int size; // 佇列資料元素個數

	// 初始化鏈佇列
	public LinkQueue() {
		front = rear = null;
		size = 0;
		maxsize = 0;
	}

	// 初始化限容量的鏈佇列
	public LinkQueue(int maxsize) {
		super();
		this.maxsize = maxsize;
	}

	// 入佇列操作
	public boolean enqueue(E item) {
		QueueNode<E> newnode = new QueueNode<E>(item);
		if (!isFull()) {
			if (isEmpty()) {
				front = newnode;
				rear = newnode;
			} else {
				rear.setNext(newnode);
				rear = newnode;
			}
			++size;
			return true;
		} else
			return false;
	}

	// 出佇列操作
	public E dequeue() {
		if (isEmpty())
			return null;
		QueueNode<E> node = front;
		front = front.getNext();
		if (front == null) {
			rear = null;
		}
		--size;
		return node.getData();

	}

	// 取對頭元素
	public E peek() {
		if (!isEmpty()) {
			return front.getData();
		} else
			return null;
	}

	// 求佇列的長度
	public int size() {
		// TODO Auto-generated method stub
		return size;
	}

	// 判斷佇列是否為空
	public boolean isEmpty() {
		if ((front == rear) && (size == 0)) {
			return true;
		} else {
			return false;
		}
	}

	// 判斷佇列是否為滿
	public boolean isFull() {
		if (maxsize != 0 && size == maxsize) {
			return true;
		} else {
			return false;
		}
	}
}

 

總結與分析

  • 位於java.util.Queue的介面擴充了java.util.Collection介面,定義了佇列存取元素的基本方法。

 

相關文章