栈的几种实现方式

116 阅读2分钟

什么是栈?

  • 栈其实就是一种数据结构,特点是先进后出,后进先出
  • 栈的底层就是一个数组

什么是栈帧?

  • 调用函数的时候,我们会为这个函数在 JVM 上开辟一块内存空间,这就叫做栈帧。

  • 先调用的函数在栈底,后调用的函数在栈顶,这个过程就叫压栈

一、使用数组

时间复杂度:

出栈:入栈:O(1) 出栈:O(1)

代码:

public class MyStack1 {

    private int[] elem;
    private int usedSize;
    
    public TestDemo2() {
        // 数组初始容量设置为 10
        this.elem = new int[10];
    }

    public void push(int val) {
        if (isFull()) {
            // 满了就扩容,这里是二倍扩容
            elem = Arrays.copyOf(elem,elem.length * 2);
        }
        elem[usedSize++] = val;
    }
    
    public int pop() {
        if (isEmpty()) {
            // 为空就返回 -1, 这里也可以抛异常
            return -1;
        }
        return elem[usedSize--];
    }

    public int peek() {
        if (isEmpty()) {
            // 为空就返回 -1, 这里也可以抛异常
            return -1;
        }
        return elem[usedSize];
    }
    
    public int size() {
        return usedSize;
    }
    
    public boolean isEmpty() {
        return usedSize == 0;
    }
    
    private boolean isFull() {
        return elem.length == usedSize;
    }
    
}

二、使用链表

时间复杂度

尾插法: 入栈:O(N) 出栈:O(N)

头插法:入栈:O(1) 出栈:O(1)

因此用链表实现栈的时候,用头插法来入栈和出栈。

代码:

// 使用链表来实现一个栈
public class MyStack2 {

    static class Node {
        int val;
        Node next;

        public Node(int val) {
            this.val = val;
        }
    }

    private Node head;
    private Node last;

    public void push(int val) {
        Node newNode = new Node(val);
        if (head == null) {
            this.head = newNode;
            this.last = newNode;
        } else {
            newNode.next = this.head;
            this.head = newNode;
        }
    }

    public int pop() {
        if (isEmpty()) {
            // 如果为空就返回 -1
            return -1;
        }
        int val = this.head.val;
        this.head = this.head.next;
        return val;
    }

    public int peek() {
        if (isEmpty()) {
            // 如果为空就返回 -1
            return -1;
        }
        return this.head.val;
    }

    public int size() {
        Node cur = head;
        int count = 0;
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

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

}

三、使用队列

题目: 用栈实现队列

时间复杂度:

出栈:入栈:O(1) 出栈:O(1)

思路:需要准备两个队列

  1. 入栈:入到不为空的队列
  2. 出栈:从不为空的队列出

代码:

public class MyStack {

    Queue<Integer> queue1;
    Queue<Integer> queue2;

    public MyStack() {
        // 初始化队列
        queue1 = new LinkedList<>();
        queue2 = new LinkedList<>();
    }

    public void push(int x) {
        // 那个队列不为空就入到那个队列
        // 都为空就默认入 queue1
        if (!queue1.isEmpty()) {
            queue1.offer(x);
        } else if (!queue2.isEmpty()) {
            queue2.offer(x);
        } else {
            queue1.offer(x);
        }
    }

    public int pop() {
        if (empty()) {
            return -1;
        }
        int size = 0;
        if (!queue1.isEmpty()) {
            // 计算 size 即队列中的元素个数 - 1
            // 将剩下的最后一个元素弹出
            size = queue1.size() - 1;
            for (int i = 0; i < size; i++) {
                queue2.offer(queue1.poll());
            }
            return queue1.poll();
        } else {
            size = queue2.size() - 1;
            for (int i = 0; i < size; i++) {
                queue1.offer(queue2.poll());
            }
            return queue2.poll();
        }
    }

    public int top() {
        if (empty()) return -1;
        int size;
        int x = 0;
        if (!queue1.isEmpty()) {
            size = queue1.size();
            for (int i = 0; i < size; i++) {
                x = queue1.poll();
                queue2.offer(x);
            }
        }
        else {
            size = queue2.size();
            for (int i = 0; i < size; i++) {
                x = queue2.poll();
                queue1.offer(x);
            }
        }
        return x;
    }

    public boolean empty() {
        return queue1.isEmpty() && queue2.isEmpty();
    }

}