狗窝:用数组实现一个栈

狗窝:用数组实现一个栈

看过西游记的同学应该记得,有一回,四人被妖怪抓住,要下蒸笼,担心猪八戒皮糙肉厚不容易熟把他放在最底下一格。八戒哇哇大叫。孙悟空却还嘲笑妖怪是雏儿,说皮厚的其实该放在上边才熟的快。小时候看这段,很精彩,但一直没去没验证这个说法的真实性,谁让大师兄看起来很厉害的样子……。哈,扯远了。举这个栗子是想用它引入咱们今天的主题——用数组来实现一个栈。

栈是一种基本的数据结构,具有后进先出(LIFO —— last in - first out)的特性。在生活中的栗子也随处可见,一叠碗、一摞书、妖怪用的蒸笼都是经典的栈结构。那么在程序里如何去实现一个栈呢?要弄清这个问题,我们先要知道栈拥有哪些行为。网上文章不少,我试着用自己的语言再描述一下:栈是一个容器,一般来说容量是固定的,我们把向这个容器中插入一个元素叫作入栈(push),把删除一个元素叫作出栈(pop),不管是入栈还是出栈,你每次的操作都只能在容器最顶上的那个位置进行。

这里写图片描述

基于这些行为,可以定义这样一个接口:

public interface IStack {
    /**
     * 入栈。先限定类型只能是String,同时不允许插入null
     *
     * @param value push value
     */
    void push(@NotNull String value);

    /**
     * 出栈
     */
    void pop();

    /**
     * 清空栈
     */
    void clean();

    /**
     * 返回栈大小
     *
     * @return stack size
     */
    int size();

    /**
     * 栈是否为空
     *
     * @return is empty
     */
    boolean isEmpty();

}

初具雏形了呢,虽然它还什么都不能做。但有了这个框架,就可以一步步往里面填东西了。接下来新建一个类,实现 IStack 接口

public class Stack implements IStack {
    private static final int DEFAULT_INCREMENT = 4;

    private String[] container;
    private int size = 0;
    private int top = -1;   // 栈顶索引

  public Stack() {
        this(DEFAULT_INCREMENT);
    }

    public Stack(int increment) {
        if (increment <= 0) {
            throw new IllegalArgumentException("Increment must be greater than zero.");
        }
        container = new String[increment];
    }
}    

实现接口方法

 @Override
    public void push(@NotNull String value) {
        top += 1;

        if (top < container.length) {
            container[top] = value;
        }

        // 1.new一个空数组,长度为container.len+1 
        // 2.把container的元素复制到temp中,并将新元素插入到数组temp尾部
        // 3.temp赋给container

        else {
            String[] temp = new String[container.length + 1];
            System.arraycopy(container, 0, temp, 0, container.length);
            temp[temp.length - 1] = value;
            container = temp;
        }

        size += 1;
    }

    @Override
    public void pop() {
        if (isEmpty()) {
            throw new StackOverflowException("The stack is empty");
        }
        this.container[top] = null;
        size -= 1;
        top -= 1;
    }

    @Override
    public void clean() {
       while (!isEmpty()) {
            pop();
        }
    }

    @Override
    public int size() {
        return size;
    }

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

现在来测试一下

public static void main(String[] args) {
        Stack<String> st1 = new Stack<>();
        st1.push("烧麦");
        st1.push("豆沙");
        st1.push("猪肉大葱");
        st1.push("老面馒头");
        st1.push("白团子");

        st1.pop();
        st1.pop();
        st1.pop();
        st1.set("芹菜香菇包");

        outputStackInfo(st1);
}

stack info : Stack{container=[烧麦, 芹菜香菇包, null, null, null]}
stack top : 1
stack size : 2
stack empty : false


到这里,我们已经基本上用数组实现了一个栈。为什么说基本上呢?因为我们只实现了接口中的几个方法。至少目前看来,它还存在以下几个缺陷:

  • 从功能上
    1. 只能存储 String 类型,如何利用泛型让它支持多种类型的存储呢。
    2. 从外部无法访问元素,是否需要对外提供 get 方法?另外,是否需要支持循环遍历。
  • 从实现细节上
    1. size 达到数组的长度时,每次增量为 1。
    2. 没有限制栈的 max size。

如果你有兴趣,可以尝试去解决一下。

参考:

  • 《算法导论》第10章:基本数据结构
  • java doc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值