数据结构和算法之【栈】

目录

栈的定义

自实现栈

定义栈接口

基于链表实现栈

基于数组实现栈

LeetCode-102题

题解

测试结果

LeetCode-232题

题解

测试结果

LeetCode-225题

题解

测试结果


栈的定义

计算机科学中,栈是一种线性数据结构,只能在它的一端添加或移除元素

  • 可以操作元素的一端叫做栈顶,另一端不能操作元素叫做栈底
  • 添加元素的操作叫做入栈(或压栈),移除元素的操作叫出栈(或弹栈)
  • 先进后出

自实现栈

可以通过多种方式来实现栈,如:链表、数组等。下面先定义栈的功能接口,然后分别用链表和数组来实现栈

定义栈接口

java 复制代码
package algorithm.stack;

/**
 * 栈接口:定义栈功能
 */
public interface Stack {
    // 栈的最大容量:1024
    int MAX_CAPACITY = 1 << 10;

    /**
     * 入栈/压栈
     */
    boolean push(Object e);

    /**
     * 出栈/弹栈
     */
    Object pop();

    /**
     * 查看栈顶元素
     */
    Object peek();

    /**
     * 栈是否空
     */
    boolean isEmpty();

    /**
     * 栈是否满
     */
    boolean isFull();
}

基于链表实现栈

只能从栈顶操作元素是栈的特点之一,即只从一端添加元素或者移除元素就行,所以这里我选择用单项链表来实现栈

java 复制代码
package algorithm.stack;

import java.util.Iterator;

/**
 * 基于链表实现栈
 */
public class LinkedListStack implements Stack, Iterable<Object> {
    // 虚拟头节点
    private final Node dummyHead = new Node();
    // 元素个数
    private int size;

    @Override
    public boolean push(Object e) {
        if (e == null) {
            throw new NullPointerException();
        }
        if (isFull()) {
            return false;
        }
        dummyHead.next = new Node(e, dummyHead.next);
        size++;
        return true;
    }

    @Override
    public Object pop() {
        Object e = peek();
        if (e != null) {
            dummyHead.next = dummyHead.next.next;
            size--;
        }
        return e;
    }

    @Override
    public Object peek() {
        if (isEmpty()) {
            return null;
        }
        return dummyHead.next.val;
    }

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

    @Override
    public boolean isFull() {
        return size == MAX_CAPACITY;
    }

    @Override
    public Iterator<Object> iterator() {
        return new Iterator<Object>() {
            Node p = dummyHead;

            @Override
            public boolean hasNext() {
                return p.next != null;
            }

            @Override
            public Object next() {
                Node node = p.next;
                p = p.next;
                return node.val;
            }
        };
    }

    /**
     * 定义数据节点
     */
    private static class Node {
        Object val;

        Node next;

        public Node() {
        }

        public Node(Object val, Node next) {
            this.val = val;
            this.next = next;
        }
    }
}

基于数组实现栈

这里再使用数组来实现栈,从数组的尾部来操作元素,性能要高一些,因为从数组0索引处添加或移除元素,会涉及到后续元素的移动,影响性能

java 复制代码
package algorithm.stack;

import java.util.Arrays;
import java.util.Iterator;

/**
 * 基于数组实现栈
 */
public class ArrayStack implements Stack, Iterable<Object> {
    // 元素个数
    private int size;
    // 存储元素的数组
    private Object[] container;
    // 默认初始化容量
    private static final int DEFAULT_INIT_CAPACITY = 16;
    // 定义一个指针,方便栈顶操作元素
    private int p = 0;

    @Override
    public boolean push(Object e) {
        if (e == null) {
            throw new NullPointerException();
        }
        if (isFull()) {
            return false;
        }
        grow(size + 1);
        addToContainer(e);
        return true;
    }

    /**
     * 扩容
     */
    private void grow(int minCapacity) {
        if (isEmpty()) {
            container = new Object[DEFAULT_INIT_CAPACITY];
            return;
        }
        int oldCapacity = container.length;
        // 扩容为原来的两倍容量
        int newCapacity = oldCapacity << 1;
        newCapacity = Math.min(MAX_CAPACITY, newCapacity);
        container = Arrays.copyOf(container, newCapacity);
    }

    /**
     * 执行添加元素
     */
    private void addToContainer(Object e) {
        container[p] = e;
        size++;
        p++;
    }

    @Override
    public Object pop() {
        Object e = peek();
        if (e != null) {
            container[p--] = null;
            size--;
        }
        return e;
    }

    @Override
    public Object peek() {
        if (isEmpty()) {
            return null;
        }
        return container[p - 1];
    }

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

    @Override
    public boolean isFull() {
        return size == MAX_CAPACITY;
    }

    @Override
    public Iterator<Object> iterator() {
        return new Iterator<Object>() {
            private int index = size - 1;

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

            @Override
            public Object next() {
                return container[index--];
            }
        };
    }
}

LeetCode-102题

题解

java 复制代码
class Solution {
    public boolean isValid(String s) {
        // check param
        if (s == null || s.length() < 2) {
            return false;
        }
        // 借助栈来解题(Java中的LinkedList可以用作栈)
        LinkedList<Character> stack = new LinkedList<>();
        for (int i = 0; i < s.length(); i++) {
            char item = s.charAt(i);
            if ('(' == item) {
                stack.push(')');
            } else if ('{' == item) {
                stack.push('}');
            } else if ('[' == item) {
                stack.push(']');
            } else {
                if (!stack.isEmpty() && item == stack.peek()) {
                    stack.pop();
                } else {
                    return false;
                }
            }
        }
        return stack.isEmpty();
    }
}

测试结果

LeetCode-232题

题解

java 复制代码
/**
 * 注:题目上说明了所有的操作都是有效的,不会抛异常
 */
class MyQueue {

    // 用于添加元素的栈
    private LinkedList<Integer> stackEnter = new LinkedList<>();
    // 用于移除元素的栈
    private LinkedList<Integer> stackExit = new LinkedList<>();

    public void push(int x) {
        stackEnter.push(x);
    }

    public int pop() {
        transferStack();
        return stackExit.pop();
    }

    private void transferStack() {
        if (!stackExit.isEmpty()) {
            return;
        }
        while (!stackEnter.isEmpty()) {
            stackExit.push(stackEnter.pop());
        }
    }

    public int peek() {
        transferStack();
        return stackExit.peek();
    }

    public boolean empty() {
        return stackEnter.isEmpty() && stackExit.isEmpty();
    }
}

测试结果

LeetCode-225题

题解

java 复制代码
/**
 * 注:题目中说明所有操作都是有效操作
 */
class MyStack {
    // Java中,LinkedList可以用作队列
    // 定义两个队列
    private final LinkedList<Integer> queueEnter = new LinkedList<>();
    private final LinkedList<Integer> queueExit = new LinkedList<>();

    public MyStack() {

    }

    public void push(int x) {
        queueEnter.offer(x);
    }

    public int pop() {
        transferQueue();
        return queueExit.poll();
    }

    private void transferQueue() {
        while (!queueEnter.isEmpty()) {
            queueExit.offer(queueEnter.poll());
        }
        int size = queueExit.size();
        for (int i = 0; i < size - 1; i++) {
            queueExit.offer(queueExit.poll());
        }
    }

    public int top() {
        int pop = pop();
        queueExit.offer(pop);
        return pop;
    }

    public boolean empty() {
        return queueEnter.isEmpty() && queueExit.isEmpty();
    }
}

测试结果

相关推荐
枫叶落雨22214 小时前
ShardingSphere 介绍
java
花花鱼14 小时前
Spring Security 与 Spring MVC
java·spring·mvc
无敌昊哥战神14 小时前
深入理解 C 语言:巧妙利用“0地址”手写 offsetof 宏与内存对齐机制
c语言·数据结构·算法
言慢行善15 小时前
sqlserver模糊查询问题
java·数据库·sqlserver
专吃海绵宝宝菠萝屋的派大星15 小时前
使用Dify对接自己开发的mcp
java·服务器·前端
XH华15 小时前
数据结构第九章:树的学习(下)
数据结构·学习
大数据新鸟15 小时前
操作系统之虚拟内存
java·服务器·网络
Tong Z15 小时前
常见的限流算法和实现原理
java·开发语言
凭君语未可15 小时前
Java 中的实现类是什么
java·开发语言
He少年15 小时前
【基础知识、Skill、Rules和MCP案例介绍】
java·前端·python