数据结构和算法之【栈】

目录

栈的定义

自实现栈

定义栈接口

基于链表实现栈

基于数组实现栈

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();
    }
}

测试结果

相关推荐
不要秃头的小孩2 小时前
力扣刷题——111.二叉树的最小深度
数据结构·python·算法·leetcode
希望永不加班2 小时前
SpringBoot 核心配置文件:application.yml 与 application.properties
java·spring boot·后端·spring
散峰而望2 小时前
【基础算法】从入门到实战:递归型枚举与回溯剪枝,暴力搜索的初级优化指南
数据结构·c++·后端·算法·机器学习·github·剪枝
liurunlin8882 小时前
HeidiSQL导入与导出数据
java
leaves falling2 小时前
有效的字母异位词
java·服务器·前端
我真会写代码2 小时前
Spring面试高频题:从基础到源码,通俗拆解+避坑指南
java·spring·面试
huaweichenai3 小时前
java的时间操作介绍
java·开发语言
毕设源码-朱学姐3 小时前
【开题答辩全过程】以 基于SpringBoot+Vue的百货商品进出货平台为例,包含答辩的问题和答案
java·spring boot·后端
左左右右左右摇晃3 小时前
Java笔记——包装类(自动拆装箱)
java·笔记·python