資料結構 三---棧

來源:互聯網
上載者:User

在學習的過程中有時會遇到一種資料結構也就是棧,這裡對棧做個詳細的瞭解。在完善這篇部落格的過程中主要參考了這兩篇博文:http://www.cnblogs.com/QG-whz/p/5170418.html#_label1_1和http://blog.csdn.net/javazejian/article/details/53362993在這裡註明出處,所涉及到的代碼皆由我用java實現。第一次修改日期是2017.8.02下午 棧簡介 棧的特點

棧(Stack)是一種線性儲存結構,也可以稱做一種操作受限的特殊的線性表,其插入和刪除操作只允許線上性表的一端進行,一般而言,把允許操作的一端稱為棧頂(Top),不可操作的一端稱為棧底(Bottom),棧頂也就是線性序列的末端。

總結有如下兩個特點:
1, 棧中的資料元素遵守”後進先出”( Last In Out First)的原則,簡稱LIFO結構。
2, 限定只能在棧頂進行插入和刪除操作。 棧的相關概念

1,棧頂與棧底:允許元素插入與刪除的一端稱為棧頂(TOP),另一端稱為棧底(BOTTOM)。
2,壓棧:棧的插入操作,叫做進棧,也稱壓棧、入棧(PUSH)。
3,彈棧:棧的刪除操作,也叫做出棧(POP)。 棧的基本運算

1,入棧(push)

在壓棧的過程中,棧頂的位置一直在”向上“移動,而棧底是固定不變的。


2,出棧(pop)

出棧的順序為3、2、1 ,順序與入棧時相反,這就是所謂的”後入先出“。
在彈棧的過程中,棧頂位置一直在”向下“移動,而棧底一直保持不變。

3,求棧的大小(size)
4,判斷棧是否為空白(isEmpty)
5,擷取棧頂元素的值(top) 棧的實現方式 java中Stack類的使用

    /**      * Stack類      * 棧:桶型或箱型資料類型,後進先出,相對堆Heap為二叉樹類型,可以快速定位並操作      * Stack<E>,支援泛型      * public class Stack<E> extends Vector<E>      * Stack的方法調用的Vector的方法,被synchronized修飾,為安全執行緒(Vector也是)      * Stack methods:      * push : 把項壓入堆棧頂部 ,並作為此函數的值返回該對象      * pop : 移除堆棧頂部的對象,並作為此函數的值返回該對象       * peek : 查看堆棧頂部的對象,,並作為此函數的值返回該對象,但不從堆棧中移除它      * empty : 測試堆棧是否為空白       * search : 返回對象在堆棧中的位置,以 1 為基數     * size:返回棧的大小       * */  
    package ca.map;      import java.util.Stack;      public class StackX {          public static void main(String[] args) {              stackMethod();          }          //stack operate          public static void stackMethod(){              //定義一個Integer泛型的Stack              Stack<Integer> stack = new Stack<Integer>();              System.out.println("建立棧stack是否為空白 : "+(stack.empty() ? "空" : stack.size()));              //push : 把項壓入堆棧頂部,傳回值泛型指定的類型              //此處將1到5壓入棧中              stack.push(1);              stack.push(2);              stack.push(3);              stack.push(4);              stack.push(5);              System.out.println("將1到5按順序壓入棧中後為:"+stack);              //empty : 測試堆棧是否為空白,size() == 0,傳回值boolean              System.out.println("值為1~5的棧中stack是否為空白 : "+(stack.empty() ? "空" : stack.size()));              //search : 返回對象在堆棧中的位置,以 1 為基數,參數:search(Object o) ,傳回值int              int oStack = stack.search(3);              System.out.println("尋找棧stack中對象3的位置elementId為 : "+oStack);              //peek : 查看堆棧頂部的對象,但不從堆棧中移除它,傳回值泛型指定的類型              int topElement =stack.peek();              System.out.println("查看stack的棧頂元素為 : "+topElement);              System.out.println("peek操作stack後為 : "+stack);              //pop : 移除堆棧頂部的對象,並作為此函數的值返回該對象,傳回值泛型指定的類型              int oRemove = stack.pop();              System.out.println("移除stack棧頂的元素為 : "+oRemove);              System.out.println("pop操作移除stack棧頂元素後為 : "+stack);          }      }  

測試結果

建立棧stack是否為空白 : 空將1到5按順序壓入棧中後為:[1, 2, 3, 4, 5]值為1~5的棧中stack是否為空白 : 5尋找棧stack中對象3的位置elementId為 : 3查看stack的棧頂元素為 : 5peek操作stack後為 : [1, 2, 3, 4, 5]移除stack棧頂的元素為 : 5pop操作移除stack棧頂元素後為 : [1, 2, 3, 4]

若集合為空白,返回 []
若集合不為空白則 [ 加上迭代元素 加上 , 最後集合無元素加上 ] eg:[1, 2, 3, 4]
棧按照儲存結構有兩種實現方式。 數組實現

棧的建立和常用方法代碼:

package stack;import java.util.EmptyStackException;public class MyStackArray<T> {    public T[] array = null; // 存放元素的數組    public  int initalSize = 5; // 棧的容量大小,預設為10    public int top = -1; // 棧頂指標 ,-1表示空棧,因為數組下標從0開始。    public int curSize;  //表示棧的當前實際容量是多大    public MyStackArray() {        this(5);    }    @SuppressWarnings("unchecked")    public MyStackArray(int Size) { // 建構函式,用於初始化棧大小        if (Size >= 0) {            this.initalSize= Size; // 棧的容量為該值            array = (T[]) new Object[Size]; // 存放棧元素數組大小的值也為該值            top = -1; // 如果棧頂指標指向-1,表示空棧,            curSize = 0;        } else {            throw new RuntimeException("初始化大小不能小於0:" + Size);        }    }    // 判斷該棧是否為空白    public boolean isEmpty() {        return top == -1 ? true : false; // 如果棧頂指標指向-1,表示空棧    }    // 擴充棧的的容量    @SuppressWarnings("unchecked")    public void expandCapacity() {        // 如果需要拓展的容量比現在數組的容量還小,則無需擴容        T[] old = array;        array = (T[]) new Object[curSize * 2 + 1];        initalSize = curSize * 2 + 1;        // 複製元素        for (int i = 0; i < top; i++)            array[i] = old[i];    }    // 進棧,先判斷棧是否已經滿了    public void push(T data) {        if (top == initalSize-1) {            expandCapacity(); // 如果棧已經滿了,則擴充容量        }        // 從棧頂添加元素        array[++top] = data; // 沒滿的話top指向的下一個元素為該元素,數組擴充        curSize++;    }    // 出棧,首先判斷是否為空白棧,為空白則報異常    public T pop() {        if (isEmpty())            new EmptyStackException();        curSize--;        return array[top--]; // 返回要刪除的元素    }    // 查看棧頂元素但不移除    public T peek() {        if (isEmpty())            new EmptyStackException();        return array[top];    }      //返回對象在堆棧中的位置,以 1 為基數    public int search(T data){        int i = top;        while(top != -1){            if(peek() != data){                top--;            }else{                break;            }        }        int result = top+1;        top = i; //top返回棧頂位置        return result;          }}

測試代碼:

package stack;public class Stack {    public static void main(String[] args) {        MyStackArray<Integer> s = new MyStackArray<Integer>();        s.push(1);        s.push(5);        s.push(3);        s.push(4);        System.out.println("棧的容量"+ s.initalSize);        System.out.println("棧頂元素"+s.peek());        System.out.println("搜尋元素的位置" +s.search(5));        System.out.println("出棧元素是"+s.pop());        System.out.println("出棧一次後棧頂" +s.peek());        s.push(8);        s.push(9);        System.out.println("棧頂元素"+s.peek());        System.out.println("棧的容量"+ s.initalSize);        s.push(10);        System.out.println("棧頂元素"+s.peek());        System.out.println("棧的容量"+ s.initalSize);    }}

測試結果

棧的容量5棧頂元素4搜尋元素的位置2出棧元素是4出棧一次後棧頂3棧頂元素9棧的容量5     //注意,在這個地方由於增加元素超過總容量,所以自動擴容棧頂元素10棧的容量11
單鏈表實現



鏈表類代碼

package stack;public class Node<T> {    public T val;    public Node<T> next = null;    public Node(T val, Node<T> next) {   //構造方法,建立一個新節點        this.val = val;        this.next = next;    }}

單鏈表組成的棧代碼

package stack;public class MyStackList<T> {    public Node<T> top; // 棧頂元素    public int curSize;    // 判斷該棧是否為空白    public boolean isEmpty() {        return curSize == 0 ? true : false;    }    // 進棧,先判斷棧是否已經滿了    public void push(T val) {        if (val == null) {            System.out.println("新加節點的資料不能為null");        }        if (top == null) {            top = new Node<T>(val, null); // 如果當前為空白棧,無節點,則進來的節點為第一個節點        } else if (top.val == null) {            top.val = val; // 如果當前top不為null,但是其中的資料為null,則只需把當前的資料賦給棧頂就好        } else {            Node<T> newNode = new Node<T>(val, top);            top = newNode; // 更新棧頂        }        curSize++;    }    // 出棧,首先判斷是否為空白棧,為空白則報異常    public T pop() {        if (isEmpty()) {            System.out.println("棧為空白");        }        T oldData = top.val;        top = top.next;        curSize--;        return oldData;    }    // 查看棧頂元素但不移除    public T peek() {        if (isEmpty()) {            System.out.println("棧為空白");        }        return top.val;    }    // 返回對象在堆棧中的位置,以 1 為基數    public int search(T data) {        int count = curSize;        Node<T> temp = top;        while (temp != null) {            if (temp.val == data)                return count;            count--;            temp = temp.next;        }        return -100000;    }}

測試代碼

package stack;public class ListStack {    public static void main(String[] args) {        MyStackList<Integer> s = new MyStackList<Integer>();        s.push(1);        s.push(5);        s.push(3);          s.push(3);         System.out.println("棧的容量"+ s.curSize);        s.pop();          System.out.println("棧的容量"+ s.curSize);        System.out.println("棧頂元素"+s.peek());        System.out.println("搜尋元素的位置" +s.search(1));        System.out.println("出棧元素是"+s.pop());        System.out.println("出棧兩次後棧頂" +s.peek());        s.push(8);        s.push(9);        System.out.println("棧頂元素"+s.peek());        System.out.println("棧的容量"+ s.curSize);        s.push(10);        System.out.println("棧頂元素"+s.peek());        System.out.println("棧的容量"+ s.curSize);    }}

測試結果

棧的容量4棧的容量3棧頂元素3搜尋元素的位置1出棧元素是3出棧兩次後棧頂5棧頂元素9棧的容量4棧頂元素10棧的容量5
兩種實現的時間複雜度比較

順序棧複雜度如下:

鏈式棧複雜度如下:

由此可知棧的主要操作都可以在常數時間內完成,這主要是因為棧只對一端進行操作,而且操作的只是棧頂元素。 LinkedList實現棧

import java.util.LinkedList;/** * 基於LinkedList實現棧 * 在LinkedList實力中只選擇部分基於棧實現的介面 */public class StackList<E> {    private LinkedList<E> ll = new LinkedList<E>();    //入棧    public void push(E e){        ll.addFirst(e);    }    //查看棧頂元素但不移除    public E peek(){        return ll.getFirst();    }    //出棧    public E pop(){        return ll.removeFirst();    }    //判空    public boolean empty(){        return ll.isEmpty();    }    //列印棧元素    public String toString(){        return ll.toString();    }}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.