Java 模拟“栈数据结构”

这是之前学习中碰到的一个较好的实例,感觉很有意义,拿出来记录一下!程序的内容包括类、异常等。

代码如下:

  • 首先定义一个 MyStack 类:
/**
 * 模拟栈:使用一位数组模拟栈的数据结构,假设栈的默认容量为 5
 * 实现功能:
 *      1、可以存储 Java 中任意类型的数据
 *      2、提供 push 方法模拟压栈(栈满了,要有提示信息)
 *      3、提供 pop 方法模拟弹栈(栈空了,要有提示信息)
 *      4、设置栈帧,指向栈顶元素
 *      5、编写测试程序
 *
 */
public class MyStack {

    // 栈可以存放任意类型的数据,存到栈中即表示存到数组中
    private Object[] elements;

    // 栈帧,指向顶部元素
    private int index;

    /*
        设置 set 和 get 方法
    */
    public Object[] getElements() {
        return elements;
    }

    public void setElements(Object[] elements) {
        this.elements = elements;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    /*
            无参数的构造方法
        */
    public MyStack() {
        // 默认容量为 5
        this.elements = new Object[5];
        this.index = -1;
    }

    /*
        有参数的构造方法
    */
    public MyStack(Object[] elements) {
        this.elements = elements;
    }



    /*
         压栈方法
    */
    public void push(Object obj){
        if (this.index >= elements.length-1){
            System.out.println("栈已满,压栈失败!");
            return;
        }
//        this.index++;
        this.elements[++index] = obj;
        System.out.println("压入" + obj + "元素成功,栈帧指向:" + index);
    }

    /*
        弹栈方法
    */
    public void pop(){
        if (this.index <= -1){
            System.out.println("栈已空,弹栈失败!");
            return;
        }
        System.out.print("弹出" + elements[index] + "成功,");
        this.elements[index--] = null;
        System.out.println("栈帧指向:" + index);
    }


}
  • 然后是一个测试程序:
public class Test {
    public static void main(String[] args) {

        MyStack ms = new MyStack();
        ms.push(new Object());
        ms.push(new Object());
        ms.push(new Object());
        ms.push(new Object());
        ms.push(new Object());
        ms.push(new Object()); // 这里栈满了

        System.out.println("-------------------------------------------------------");

        ms.pop();
        ms.pop();
        ms.pop();
        ms.pop();
        ms.pop();
        ms.pop(); // 这里栈空了

    }
}

结果如下:

压入java.lang.Object@70177ecd元素成功,栈帧指向:0
压入java.lang.Object@1e80bfe8元素成功,栈帧指向:1
压入java.lang.Object@66a29884元素成功,栈帧指向:2
压入java.lang.Object@4769b07b元素成功,栈帧指向:3
压入java.lang.Object@cc34f4d元素成功,栈帧指向:4
栈已满,压栈失败!
-------------------------------------------------------
弹出java.lang.Object@cc34f4d成功,栈帧指向:3
弹出java.lang.Object@4769b07b成功,栈帧指向:2
弹出java.lang.Object@66a29884成功,栈帧指向:1
弹出java.lang.Object@1e80bfe8成功,栈帧指向:0
弹出java.lang.Object@70177ecd成功,栈帧指向:-1
栈已空,弹栈失败!

可以看出:最后进栈的元素最先被弹出来,达到了实现的目标

但是这里的 “栈满” 或者 “栈空” 的表达可以考虑写的更完美一些,比如使用异常机制来做。因此下面再加入一个自定义的异常类,取名:MyStackOperationException

  • MyStackOperationException 代码:
public class MyStackOperationException extends Exception{
    /*
        无参数的异常构造方法
     */
    public MyStackOperationException(){

    }
    /*
        有参数的异常构造方法
     */
    public MyStackOperationException(String s){
        super(s);
    }
}
  • 此时的 MyStack 代码代码修改为:
/**
 * 模拟栈:使用一位数组模拟栈的数据结构,假设栈的默认容量为 5
 * 实现功能:
 *      1、可以存储 Java 中任意类型的数据
 *      2、提供 push 方法模拟压栈(栈满了,要有提示信息)
 *      3、提供 pop 方法模拟弹栈(栈空了,要有提示信息)
 *      4、设置栈帧,指向栈顶元素
 *      5、编写测试程序
 *
 */
public class MyStack {

    // 栈可以存放任意类型的数据,存到栈中即表示存到数组中
    private Object[] elements;

    // 栈帧,指向顶部元素
    private int index;

    /*
        设置 set 和 get 方法
    */
    public Object[] getElements() {
        return elements;
    }

    public void setElements(Object[] elements) {
        this.elements = elements;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    /*
            无参数的构造方法
        */
    public MyStack() {
        // 默认容量为 5
        this.elements = new Object[5];
        this.index = -1;
    }

    /*
        有参数的构造方法
    */
    public MyStack(Object[] elements) {
        this.elements = elements;
    }

    /*
         压栈方法
    */
    public void push(Object obj) throws MyStackOperationException {
        if (this.index >= elements.length-1){
//            System.out.println("栈已满,压栈失败!");
//            return;
            throw new MyStackOperationException("栈已满,压栈失败!");
        }
//        this.index++;
        this.elements[++index] = obj;
        System.out.println("压入" + obj + "元素成功,栈帧指向:" + index);
    }

    /*
        弹栈方法
    */
    public void pop() throws MyStackOperationException {
        if (this.index <= -1){
//            System.out.println("栈已空,弹栈失败!");
//            return;
            throw new MyStackOperationException("栈已空,弹栈失败!");
        }
        System.out.print("弹出" + elements[index] + "成功,");
        this.elements[index--] = null;
        System.out.println("栈帧指向:" + index);
    }


}
  • 再次测试:
public class Test {
    public static void main(String[] args) {

        MyStack ms = new MyStack();
        try {
            ms.push(new Object());
            ms.push(new Object());
            ms.push(new Object());
            ms.push(new Object());
            ms.push(new Object());
            ms.push(new Object()); // 这里栈满了
        } catch (MyStackOperationException e) {
//            e.printStackTrace();
            System.out.println(e.getMessage());
        }

        System.out.println("-------------------------------------------------------");

        try {
            ms.pop();
            ms.pop();
            ms.pop();
            ms.pop();
            ms.pop();
            ms.pop(); // 这里栈空了
        } catch (MyStackOperationException e) {
//            e.printStackTrace();
            System.out.println(e.getMessage());
        }

    }
}

结果如下:

压入java.lang.Object@70177ecd元素成功,栈帧指向:0
压入java.lang.Object@1e80bfe8元素成功,栈帧指向:1
压入java.lang.Object@66a29884元素成功,栈帧指向:2
压入java.lang.Object@4769b07b元素成功,栈帧指向:3
压入java.lang.Object@cc34f4d元素成功,栈帧指向:4
栈已满,压栈失败!
-------------------------------------------------------
弹出java.lang.Object@cc34f4d成功,栈帧指向:3
弹出java.lang.Object@4769b07b成功,栈帧指向:2
弹出java.lang.Object@66a29884成功,栈帧指向:1
弹出java.lang.Object@1e80bfe8成功,栈帧指向:0
弹出java.lang.Object@70177ecd成功,栈帧指向:-1
栈已空,弹栈失败!