【Java】 大話數據結構(7) 循環隊列和鏈隊列

 

本文根據《大話數據結構》一書,實現了Java版的循環隊列、鏈隊列java

隊列:只容許在一端進行插入操做,而在另外一端進行刪除操做的線性表。node

 

1.循環隊列數組

  隊列的順序儲存結構:用數組存儲隊列,引入front指針指向隊頭元素,rear指針指向隊尾元素的下一個位置,當front=rear時,爲空隊列,結構以下圖所示。數據結構

 

 

  當執行入隊操做時,若數組尾部已滿,而數組前部因有元素出隊而有空位時,咱們把新插入的元素從頭開始入隊,這樣就相似於頭尾相接的結構。ide

  隊列的這種頭尾相接的順序存儲結構稱爲循環隊列,以下圖所示。測試

  上面隊列的定義中提到,當front=rear時,爲空隊列,而在循環隊列中,隊列滿時,front也等於rear,將沒法判斷隊滿和空的狀況。this

    一種辦法是設置一個標誌變量flag,當front=rear時,經過判斷flag是0仍是1來肯定隊列滿空狀況;spa

    另外一種方法是,在數組中只剩一個空閒單位時,定義爲隊列滿,以下圖所示。(本文程序採用這種辦法)指針

   由於rear可能比front大,也可能比front小,因此隊列滿的條件應該爲:(rear+1)%maxSize==front;同理,隊列長度的計算公式爲:(rear-front+maxSize)%maxSizecode

  實現程序:

/**
 * <循環隊列>
 * 
 * 注意點:表長的表示、隊列滿的判斷、front和rear的改變
 * 
 * @author Lai
 *
 */
public class SqQueue<E> {
	private E[] data;
	private int front;
	private int rear;
	private int maxSize;
	private static final int DEFAULT_SIZE= 10;
	
	/*
	 * 初始化
	 */
	public SqQueue(){
		this(DEFAULT_SIZE);
	}
	public SqQueue(int maxSize){
		data=(E[]) new Object[maxSize];
		this.maxSize=maxSize;
		front=0;
		rear=0;
	}
	
	/*
	 * 求循環隊列長度
	 */
	public int getLength() {
		return (rear-front+maxSize)%maxSize;
	}
	
	/*
	 * 入隊操做
	 */
	public void enQueue(E e) {
		if((rear+1)%maxSize==front)
			throw new RuntimeException("隊列已滿,沒法入隊!");
		data[rear]=e;
		rear=(rear+1)%maxSize;
		//不是rear=rear+1,當rear在數組尾部時,後移一位會轉到數組頭部
	}
	
	/*
	 * 出隊操做
	 */
	public E deQueue() {
		if(rear==front) 
			throw new RuntimeException("隊列爲空!");
		E e=data[front];
		front=(front+1)%maxSize;
		//不是front++,理由同rear
		return e;
	}
	
	/*
	 * 打印操做
	 */
	public void printQueue() {
		int k=front;
		for(int i=0;i<getLength();i++) {
			System.out.print(data[k]+" ");
			k=(k+1)%maxSize;
		}
		System.out.println();
	}
	
	/*
	 * 測試代碼
	 */
	public static void main(String[] args) {
		SqQueue<String> aQueue=new SqQueue<>(5);	
		aQueue.enQueue("a");
		aQueue.enQueue("b");
		aQueue.enQueue("c");
		aQueue.enQueue("d");
		aQueue.printQueue();
		System.out.println("-----");
		aQueue.getLength();
		aQueue.deQueue();
		aQueue.deQueue();
		aQueue.enQueue("e");
		aQueue.printQueue();
	}
	
}

  

a b c d 
-----
c d e 
SqQueue

 

2.隊列的鏈式存儲結構

  用單鏈表存儲隊列,稱爲鏈隊列

  定義front指針指向頭結點,rear指針指向終端結點,空隊列時,front和rear都指向頭結點。

    

  實現程序:

/**
 * 鏈隊列
 * 
 * 注意點:出隊操做時,若隊頭是隊尾(即隊中僅有一個結點),則刪除後要將rear指向頭結點。
 * 
 * @author Yongh
 *
 * @param <E>
 */
public class LinkQueue<E> {
	private QNode front,rear;
	private int count;
	
	class QNode{
		E data;
		QNode next;
		public QNode(E data,QNode next) {
			this.data=data;
			this.next=next;
		}
	}
	
	public LinkQueue() {
		front=new QNode(null, null);
		rear=front;
		count=0;
	}
	
	/*
	 * 入隊操做
	 */
	public void enQueue(E e) { 
		QNode node=new QNode(e, null);
		rear.next=node;
		rear=node;
		count++;
	}
	
	/*
	 * 出隊操做
	 */
	public E deQueue() {
		if(rear==front)
			throw new RuntimeException("隊列爲空!");
		QNode node=front.next;
		E e=node.data;
		front.next=node.next;
		//若隊頭是隊尾,則刪除後要將rear指向頭結點。
		if(rear==node)
			rear=front;
		node=null;
		count--;
		//經過count來判斷,可能更容易理解
		//if(count==0)
		//	rear=front;
		return e;
	}
	
	/*
	 * 獲取隊列長度
	 */
	public int getLength() {
		return count;
	}
	
	/*
	 * 打印輸出隊列
	 */
	public void printQueue() {
		if(count==0) {
			System.out.println("空隊列");	
		}else {
			QNode node=front;
			for(int i=0;i<count;i++) {
				node=node.next;
				System.out.print(node.data+" ");
			}
			System.out.println();
		}
	}
	
	/*
	 * 測試代碼
	 */
	public static void main(String[] args) {
		LinkQueue<String> lQueue =new LinkQueue<>();
		lQueue.printQueue();
		lQueue.enQueue("A");
		lQueue.enQueue("B");
		lQueue.enQueue("c");
		lQueue.enQueue("D");
		lQueue.printQueue();
lQueue.deQueue(); lQueue.deQueue(); lQueue.enQueue("E"); lQueue.printQueue(); } }

  

空隊列
A B c D 
c D E 
LinkQueue

 

3.循環隊列和鏈隊列的選擇

  基本操做時間都爲O(1)。但鏈隊列每次申請和釋放結點會存在一點時間開銷,且其須要存儲一個指針域;而循環隊列必須固定空間長度,存在空間浪費問題,且沒鏈隊列靈活。

  綜上,在能夠肯定隊列長度最大值的狀況下,建議用循環隊列;當沒法預估隊列的長度時,使用鏈隊列

相關文章
相關標籤/搜索