1. 程式人生 > >java 佇列與棧實現(連結串列與陣列)

java 佇列與棧實現(連結串列與陣列)

我們經常會問到java資料結構可以怎麼實現,看過了演算法之後得到很大啟發,這裡整理如下。

佇列是一種先進先出(FIFO)的集合模型,而棧則是後進先出(LIFO)的集合模型,我們經常使用它們用來儲存元素的相對順序。Java中在java.util.LinkedList類中實現了關於佇列和棧的實現,但是這是一個寬介面的例子,這裡我們自己實現它以研究它的思路。

有兩種基礎可以用來實現:陣列和連結串列

我們實現棧的基本要素如下:

int N 代表棧的容量

boolean isEmpty()用來判斷棧是否為空

int size()返回棧的容量

void push()進棧操作,每次棧頂新增元素

T pop()出棧操作,由於出棧後棧中元素會得到釋放,因此我們需要一個返回值紀錄出棧元素以便操作。這裡返回值為一個範型,可以把範型理解為佔位符,即開始時不規定型別是什麼,到後來用到時再定義,這裡範型可以為任何類。

陣列實現:

由於陣列在初始化時必須設定儲存容量,而我們並不知道我們的棧與佇列需要多大的儲存空間,因此我們對思路是在對元素進行進入操作時與容量大小進行比較,關鍵思路是如果超過了則對容量進行“擴容”,即複製一份陣列並將原來那份廢棄。在這裡對元素使用率進行了判斷,使其不回低於1/4.

public class StackInArray<T> implements Iterable<T> {

	private T[] a = (T[]) new Object[1];

	private int N = 0;

	public boolean isEmpty() {
		return N == 0;
	}

	public int size() {
		return N;
	}

	private void resize(int max) {
		T[] temp = (T[]) new Object[max];
		for (int i = 0; i < N; i++) {
			temp[i] = a[i];
		}
		a = temp;

	}

	public void push(T t) {
		if (N == a.length)
			resize(a.length << 1);//移位操作,相當於*2,感覺更能理解擴容一倍的意思。
		a[N++] = t;
	}

	public T pop() {
		T t = a[--N];
		a[N] = null;
		if (N > 0 && N == a.length / 4)
			resize(a.length >> 1);
		return t;
	}

	@Override
	public Iterator<T> iterator() {
		return new ArrayIterator();
	}

	private class ArrayIterator implements Iterator<T> {

		private int i = N;

		@Override
		public boolean hasNext() {
			return i > 0;
		}

		@Override
		public T next() {
			return a[--i];
		}

	}

}

這裡棧的基本元素為一個範型陣列。這裡新增了一個void resize(int max)方法用來對陣列進行大小調整。

當我們進棧和出棧時,實際上是對陣列中最後一個標記

看完了陣列實現的棧我們接下來看由連結串列實現的棧,首先複習一下連結串列。

連結串列定義如下:連結串列時一種遞迴的資料結構,它或者為空,或者是指向一個結點的引用,該結點含有一個範型的元素和一個指向另一條連結串列的引用。

在java中,我們可以用一個巢狀類定義結點實現連結串列

	private class Node {
		T t;
		Node next;

	}

用連結串列實現的棧基本操作與用陣列實現棧的操作一致,只不過我們這裡用Node資料型別替代陣列,因此在初始化的時候不需要定義棧的大小。

public class StackInChain<T> implements Iterable<T> {

	private Node first;// 棧頂
	private int N;// 容量

	private class Node {
		T t;
		Node next;

	}

	public boolean isEmpty() {
		return first == null;
	}

	public int size() {
		return N;
	}

	public void push(T t) {
		Node oldFirst = first;
		first = new Node();
		first.t = t;
		first.next = oldFirst;
		N++;
	}
	
	public T pop(){
		T t=first.t;
		first=first.next;
		N--;
		return t;
	}

}

連結串列實現的棧思路很明顯,每當push時就在頭節點前新增一個節點,使其作為新的頭節點,並使容量自增即可。出棧時將頭節點向後移一位即可。

資料結構 優點 缺點
陣列 通過索引可以直接訪問任意元素 在初始化時就需要知道元素的數量
連結串列 使用的空間大小與元素數量正比 需要通過索引訪問任意元素