資料結構-棧(通過陣列和單向連結串列實現)

Shawn Jeon發表於2020-10-12

概述

  1. 棧是一個先入後出(FILO, First In Last Out)的有序列表
  2. 棧的出/入操作限制只能線上性表的同一個端進行

應用場景

  1. 子程式的呼叫: 在跳往子程式前, 會先將下一個指令的地址存到棧中, 直到子程式執行完後再將地址取出, 回到原來的位置 如瀏覽器的後退/向前, JVM的虛擬機器棧
  2. 表示式的轉換(如 中綴表示式轉字尾表示式)與求值
  3. 二叉樹的遍歷
  4. 圖形的深度優先(depth-first)搜尋法

通過陣列實現


/** 定義陣列棧*/
class ArrayStack {
    /** 棧大小*/
    private int maxSize;
    /** 通過該陣列存放資料, 模擬棧資料結構*/
    private int[] stack;
    /** 棧頂的 index, 初始值為-1*/
    private int top = -1;

    public ArrayStack(int maxSize) {
        this.maxSize = maxSize;
        stack = new int[maxSize];
    }

    /** 棧滿*/
    public boolean isFull() {
        return top == maxSize - 1;
    }

    /** 棧空*/
    public boolean isEmpty() {
        return top == -1;
    }

    /** 入/壓棧*/
    public void push(int value) {
        if (isFull()) {
            System.out.println("入棧失敗, 棧已滿!");
            return;
        }
        top++;
        stack[top] = value;
    }

    /** 出/彈棧*/
    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("出棧失敗, 沒有資料!");
        }
        int value = stack[top];
        top--;
        return value;
    }

    /** 從棧頂開始列印所有內容*/
    public void list() {
        if (isEmpty()) {
            System.out.println("列印失敗, 沒有資料!");
            return;
        }
        for (int i = top; i >= 0; i--) {
            System.out.printf("stack[%d]=%d\n", i, stack[i]);
        }
    }
}

public class ArrayStackApp {
    public static void main(String[] args) {
        System.out.println("push(新增資料到棧頂)");
        System.out.println("pop(從棧取資料)");
        System.out.println("show(列印棧所有內容)");
        System.out.println("exit(退出程式)");
        /** 建立陣列棧例項*/
        ArrayStack stack = new ArrayStack(3);
        String command;
        boolean loop = true;
        Scanner scanner = new Scanner(System.in);
        while (loop) {
            System.out.println("請輸入命令!");
            command = scanner.next();
            switch (command) {
                case "show":
                    stack.list();
                    break;
                case "push":
                    System.out.println("請輸入數值!");
                    int value = scanner.nextInt();
                    stack.push(value);
                    break;
                case "pop":
                    try {
                        int result = stack.pop();
                        System.out.printf("資料 %d已出棧!\n", result);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case "exit":
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }

        System.out.println("程式結束!");
    }

}

通過單向連結串列實現


/** 定義節點*/
class Node {
    int no;
    Node next;

    /** 建立一個新的節點, 同時 next指向, 之前的棧頂節點*/
    public Node(int no, Node next){
        this.no = no;
        this.next = next;
    }

    public int getNo() {
        return no;
    }
}

/** 定義不帶頭的單向連結串列棧*/
class ListStack {
    /** 棧大小*/
    int size;
    /** 棧內有效節點個數*/
    int count;
    /** 棧頂節點*/
    Node currentNode;

    public ListStack(int size) {
        this.size = size;
        this.count = 0;
        this.currentNode = null;
    }

    /** 棧滿*/
    public boolean isFull() {
        return count == size ? true: false;
    }

    /** 棧空*/
    public boolean isEmpty() {
        return count == 0 ? true: false;
    }

    /** 入/壓棧*/
    public void push(int value) {
        if (isFull()) {
            System.out.println("入棧失敗, 棧已滿!");
            return;
        }
        /** 新建節點, 再將它設為棧頂節點, 此節點的 next是引用了, 之前的棧頂節點*/
        currentNode = new Node(value, currentNode);
        /** 遞增有效節點個數*/
        count++;
    }

    /** 出/彈棧*/
    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("出棧失敗, 沒有資料!");
        }
        int no = currentNode.getNo();
        /** 將當前下一個節點覆蓋當前節點*/
        currentNode = currentNode.next;
        /** 遞減有效節點個數*/
        count--;
        return no;
    }

    /** 列印棧頂的節點內容*/
    public void peak(){
        if (isEmpty()) {
            System.out.println("列印失敗, 沒有資料!");
            return;
        }
        System.out.println(currentNode.getNo());
    }

    /** 列印棧的所有節點內容*/
    public void show(){
        if (isEmpty()) {
            System.out.println("列印失敗, 沒有資料!");
            return;
        }

        Node temp = currentNode;
        int i = count;
        while (true) {
            if (temp == null) {
                return;
            }
            System.out.printf("stack[%d]=%d\n", i, temp.getNo());
            i--;
            temp = temp.next;
        }
    }
}

public class SingleLinkedListStackApp {
    public static void main(String[] args) {
        System.out.println("push(新增資料到棧頂)");
        System.out.println("pop(從棧取資料)");
        System.out.println("peak(列印棧頂的節點內容)");
        System.out.println("show(列印棧的所有節點內容)");
        System.out.println("exit(退出程式)");
        /** 建立連結串列棧例項*/
        ListStack stack = new ListStack(3);
        String command;
        boolean loop = true;
        Scanner scanner = new Scanner(System.in);
        while (loop) {
            System.out.println("請輸入命令!");
            command = scanner.next();
            switch (command) {
                case "push":
                    System.out.println("請輸入數值!");
                    int value = scanner.nextInt();
                    stack.push(value);
                    break;
                case "pop":
                    try {
                        int result = stack.pop();
                        System.out.printf("資料 %d已出棧!\n", result);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case "peak":
                    stack.peak();
                    break;
                case "show":
                    stack.show();
                    break;
                case "exit":
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }

        System.out.println("程式結束!");
    }

}

如果您覺得有幫助,歡迎點贊哦 ~ 謝謝!!

相關文章