自己实现集合框架(十):顺序栈的实现

312 阅读3分钟

这是系列文章,每篇文章末尾均附有源代码地址。目的是通过模拟集合框架的简单实现,从而对常用的数据结构和java集合有个大概的了解。当然实现没有java集合的实现那么复杂,功能也没有那么强大,但是可以通过这些简单的实现窥探到底层的一些共性原理。

一. 顺序栈

在前面的文章自己实现集合框架(十一):栈接口中介绍了栈的相关概念,那么什么是顺序栈呢?顺序栈指采用顺序储存结构储存数据元素的栈,比如采用数组来存放数据元素。栈的特点是只能在栈顶进行操作,后进先出,所以A,B,C,D四个元素的出栈入栈状态变化过程如下图所示:

二. 顺序栈实现

1. 定义顺序栈

在前面的文章自己实现集合框架(十一):栈接口中已经定义了栈接口,顺序栈类SeqStack实现栈接口SStack类,并实现栈接口中定义的方法,代码如下所示:

package org.light4j.dataStructure.linearList.stack.sequence;

import org.light4j.dataStructure.linearList.stack.SStack;

public class SeqStack<E> implements SStack<E> {
    private Object[] value;// 储存栈的数据元素的数组
    private int top;// 栈顶元素下标

    public SeqStack() {// 构造默认容量的空栈
        this(16);// 初始化栈的容量为16
    }

    public SeqStack(int capacity) {// 构造指定容量的空栈
        this.value = new Object[Math.abs(capacity)];
        this.top = -1;// 栈顶下标初始化为-1
    }
}

代码解释:

定义了两个构造函数,一个无参的构造函数,栈的容量默认是16,另外一个有参的构造函数,可以指定栈的容量。

Math.abs(capacity)取栈容量的绝对值,做容错处理,防止传入负数的情况。

2. 判断栈是否为空

     /**
     * 判断栈是否为空,若为空则返回true
     * 
     * @return
     */
    @Override
    public boolean isEmpty() {
        return this.top == -1;
    }

代码解释:

判断栈是否为空的条件是根据栈顶元素的索引top是否为-1作为依据。

3. 入栈

      /**
     * 元素入栈,成为新的栈顶元素,若操作成功返回true
     */
    @Override
    public boolean push(E element) {
        if (element == null) {// 元素不允许为空
            return false;
        }
        if (this.top == value.length - 1) {// 栈满则需要扩充容量
            Object[] temp = this.value;
            this.value = new Object[temp.length * 2];// 扩充数组容量为原来的数组容量的两倍
            for (int i = 0; i < temp.length; i++) {// 复制元素到新的数组
                this.value[i] = temp[i];
            }
        }
        this.top++;// 栈顶加1
        this.value[top] = element;// 把入栈的元素置于栈顶
        return true;
    }

4.出栈

/**
     * 元素出栈,返回当前栈顶元素,栈顶元素改变,若栈为空则返回null
     */
    @SuppressWarnings("unchecked")
    @Override
    public E pop() {
        if (isEmpty()) {// 如果是空栈则返回null
            return null;
        }
        return (E) this.value[top--];// 取出栈顶元素,栈顶元素改变,top减1
    }

5. 取栈顶元素

        /**
     * 取栈顶元素值,元素未出栈,栈顶元素未改变
     */
    @SuppressWarnings("unchecked")
    @Override
    public E get() {// 如果是空栈则返回null
        if (isEmpty()) {
            return null;
        }
        return (E) this.value[top];// 返回栈顶元素,栈顶元素未改变,top不变
    }

6.重写toString()方法

     /**
     * 返回栈中各元素的字符串表示
     */
    @Override
    public String toString() {
        String str = "(";
        for (int i = top; i >= 0; i--) {// 从栈顶开始遍历
            if (this.value[i] != null) {
                if (i == 0) {// i为0则是栈底元素
                    str += this.value[i];
                    // break;// 遍历完栈顶元素跳出循环
                } else {
                    str += this.value[i] + ",";
                }
            }
        }
        return str + ")";
    }

代码解释:

返回栈中各元素的字符串表示,从栈顶开始遍历到栈底元素结束。

三. 测试

package org.light4j.dataStructure.linearList.stack.sequence;

import org.light4j.dataStructure.linearList.stack.SStack;

public class Test {
    public static void main(String[] args) {
        SStack<String> stack = new SeqStack<String>();
        System.out.println(stack.isEmpty());//判空
        stack.push("A");//入栈
        stack.push("B");
        stack.push("C");
        System.out.println(stack.toString());
        stack.pop();// 出栈
        stack.push("D");
        stack.get();// 取栈顶元素
        System.out.println(stack.toString());
        System.out.println(stack.isEmpty());//判空
    }
}

运行结果如下图所示:

四.时间复杂度分析

由于栈只能在栈顶位置进行插入和删除,所以入栈push(),出栈pop()和获取栈顶元素get()的时间复杂度为O(1),当需要扩充容量时,入栈操作push()的时间复杂度为O(n)

五.源代码示例

github地址:点击查看
码云地址:点击查看

打赏 欢迎关注人生设计师的微信公众账号
公众号ID:longjiazuoA