本文整理來源 《輕鬆學算法——互聯網算法面試寶典》/趙燁 編著面試
棧是有着特殊規則的數據結構,棧有着重要的一個特色——後進先出(LIFO, Last In First Out),也能夠叫作先進後出(FILO, First In Last Out),咱們不管如何只可以從一端去操做元素。算法
棧又叫作堆棧(Stack), 這裏說明一下不要將它和堆混淆。實際上堆和棧是兩種不一樣的概念,棧是一種只能在一段進行插入和刪除的線性數據結構。編程
通常來講,棧主要有兩個操做:一個是進棧(PUSH),又叫做入棧、壓棧;另外一個是出棧(POP),或者叫做退棧。數組
棧是一種比較簡單的數據結構。數據結構
棧通常使用一段連續的空間進行存儲,一般預先分配一個長度,能夠簡單地使用數組去實現。編程語言
棧只有一個方向能夠對棧內的元素進行操做,而從棧中最下面的一個元素稱爲棧底,通常是數組的第0個元素,而棧頂是棧內最後放入的元素。函數
通常而言,定義一個棧須要初始的大小,這就是棧的初始容量。當須要放入的元素大於這個容量,就須要擴容。測試
棧出入元素的操做以下。例如咱們初始化一個長度爲10的數組,並想其中放入元素,根據棧的定義,只能從數組的一端放入元素,咱們設定這一段爲數組中較大下標方向。咱們放入第一個元素,因爲棧內沒有元素,咱們第一個元素落到數組的第0個下標的位置上;接着放入第二個元素,第二個元素該放入到下標爲1的位置上;以此類推,以後咱們放入第五個元素時,放入棧中的下標第4個位置上。如今進行出棧操做,出棧智能從一端操做,咱們以前設定只能從下標較大的方向操做,所以須要肯定數組中下標最大的方向中存在棧元素的位置下標是多少。咱們通常會在棧中作個計數器來記錄這個值。如今棧中有5個元素,因此講數組中的第五個位置也就是下標爲4的元素出棧。此時數組中只剩下4個元素了。this
public class Stack<T> { private int size = 0; private static final int DEF_INITIAL = 10; private Object[] array; public Stack() { this(DEF_INITIAL); } public Stack(int init) { if (init <= 0) { init = DEF_INITIAL; } array = new Object[init]; } /** * 入棧 * * @param item 入棧元素 */ public void push(T item) { if (size == array.length) { array = Arrays.copyOf(array, size * 2); } array[size++] = item; } /** * 獲取棧頂元素,可是沒有出棧 * @return 棧頂元素 */ @SuppressWarnings("unchecked") public T peek(){ if (size == 0){ throw new IndexOutOfBoundsException("棧頂已經空"); } return (T) array[size - 1]; } /** * 出棧,同時獲取棧頂元素 * @return 棧頂元素 */ public T pop(){ T item = peek(); //直接使元素個數減1,不須要真的清除,下次入棧會覆蓋舊元素的值 size--; return item; } /** * 棧是否滿了 * @return 棧是否滿了 */ public boolean isFull(){ return size == array.length; } /** * 棧是否爲空棧 * @return 是否爲空棧 */ public boolean isEmpty(){ return size == 0; } public int size(){ return size; } }
在實現思考當中,第一步是寫出來,第二步是擴容,第三步是考慮到異常狀況。一個數據結構的實現或多或少總會有些東西能夠擴展的,想到多少寫多少,在面試或筆試必定會有所加分的。code
測試代碼:
public class StackTest { @Test public void main(){ //爲了查看效果,初始數組長度設置爲1 Stack<Integer> stack = new Stack<>(1); stack.push(1); stack.push(2); //棧內的元素爲2,數組長度也爲2 Assert.assertEquals(2,stack.size()); stack.push(3); //棧內元素個數爲3,當前數組長度爲4 Assert.assertEquals(3,stack.size()); Assert.assertEquals(4,stack.getLength()); //獲取棧頂元素,爲3,可是沒有出棧 Assert.assertEquals(3,(int)stack.peek()); Assert.assertEquals(3,stack.size()); //棧頂元素出棧,返回3 Assert.assertEquals(3,(int)stack.pop()); //棧頂元素出棧,返回2 Assert.assertEquals(2,(int)stack.pop()); //出棧2次,棧內元素爲1 Assert.assertEquals(1,stack.size()); } }
棧的特色顯而易見,只能在一段操做,遵循先進後出或者後者先出的原則。
因爲棧具有先進後出的特色,因此逆序輸出是其中一個很是簡單的應用。首先把全部的元素按照元素入棧,而後把全部的元素出棧並輸出,輕鬆實現逆序輸出。
在編程語言中,通常括號都是成對出現的,好比「[」和「]」「{」和「}」「(」和「)」「<」和「>」(這裏排除大於小於號的做用).
凡是遇到括號的前半部分,即爲入棧符號(push);凡是遇到括號的後半部分,就比對是否與棧頂元素相匹配(peek),若是相匹配則出棧(pop),不然就是匹配出錯。
經過求餘法,能夠將十進制數轉換爲其餘進制,好比轉爲8進制,則將原十進制數除以8,記錄餘數,而後繼續將商除以8,一直到商等於0爲止,最後將餘數倒着寫出來就好了。
常據說到編程語言調用中的「函數棧」,就是在咱們調用方法時計算機會執行PUSH方法,記錄調用,在return時也就是方法結束以後,執行POP方法,完成先後對應