线性表——栈(java实现)

一,受限的线性表

在数据结构中,栈和队列也是线性表,只不过是它们的操作受到一定的限制。

二, 栈

栈是一种线性表——受限的线性表,其插入和删除操作都在表的同一端进行。其中插入和删除元素的一端 称为栈顶,另一端称为栈底,不含任何元素的栈称为空栈。栈的特点是后进先出(last in first out,LIFO)。


三,栈的实现

栈的实现可以借助于顺序表或者链表来实现,用顺序表实现的栈称为顺序栈,用链表实现的栈称为链栈。这里我们采用顺序表来实现顺序栈。要用顺序表的方式实现栈,我们需要重用之前的代码,重用代码又分为两种方式,继承和聚合,这里分别采用继承和聚合的方式实现。


继承方式
继承方式实现的话会暴露父类的方法,比如栈只有push,pop,isEmpty,peek这些方法,继承MyArrayList的话则会暴露父类中诸如add,remove,set,indexOf等方法,使用者调用这些方法则会破坏栈的结构,个人喜欢采用聚合方式实现。

public class MyArrayStack2<T> extends MyArrayList<T> {
    //调用父类的构造方法
    public MyArrayStack2()
    {
        super();
    }
    public boolean push(T data)//调用父类的add方法,在栈底插入元素
    {
        return super.add(0, data);
    }
    public T pop()//调用父类的remove方法,删除栈底元素
    {
        return super.remove(0);
    }
    public T peek()//调用父类的get方法,查看栈底元素
    {
        return super.get(0);
    }
    @Override
    public boolean isEmpty() {  //和父类的方法一样,其实没必要重写
        return super.isEmpty();
    }
}

聚合方式

public class MyArrayStack<T> {
    MyArrayList<T> stack;   //聚合方式实现顺序栈,定义一个顺序表,用来存储数据
    public MyArrayStack()
    {
        stack = new MyArrayList<T>();//初始化顺序表
    }
    public boolean push(T data)//调用顺序表的add方法,在栈底插入元素
    {
        stack.add(0, data);
        return true;
    }
    public T pop()//调用顺序表的remove方法,删除栈底元素
    {
        return stack.remove(0);
    }
    public T peek()//调用顺序表的get方法,查看栈底元素
    {
        return stack.get(0);
    }
    public boolean isEmpty()//调用顺序表的isEmpty方法,判断栈是否为空
    {
        return stack.isEmpty();
    }
}

四,测试

import static java.lang.System.*;
public class TestStack {
    public static void main(String[] args) {
        MyArrayStack<String> stack1 = new MyArrayStack<String>();
        MyArrayStack2<String> stack2 = new MyArrayStack2<String>();
        stack1.push("北京");
        stack1.push("我");
        stack1.push("爱");
        stack1.push("你");
        while(!stack1.isEmpty())
        {
            out.print(stack1.pop()+" ");
        }
        out.println();
        stack2.push("数据结构");
        stack2.push("操作系统");
        stack2.push("软件工程");
        stack2.push("计算机图形学");
        stack2.push("数据库原理");

        out.println("栈顶元素为:"+stack2.peek());
        stack2.add(5,"我是栈底元素"); //这里调用了父类的add方法,在栈底插入了元素,                                       
        while(!stack2.isEmpty())        //已经破坏了栈后进先出的原则
        {
            out.print(stack2.pop()+" ");
        }
        out.println();
    }
}

运行结果:

你 爱 我 北京 
栈顶元素为:数据库原理
数据库原理 计算机图形学 软件工程 操作系统 数据结构 我是栈底元素 

这样我们便借助之前的代码实现了栈。关于上面用到的类MyArrayList请参考以下文章: https://blog.csdn.net/YIXIANG0234/article/details/79901468

五,栈的数组实现

关于栈的实现方法除了上面说的采用顺序表和链表的方式外,还可以用数组来实现,不过数组实现有缺陷,就是必须事先知道栈的大小,否则创建出来的栈容量可能不合理,即过大(浪费空间)或过小(数据溢出),因此最好是使用顺序表或者链表的方式实现。

public class ArrayStack<T> {
    private int top;    //指向栈底元素
    private int maxSize;//栈的容量
    private Object[] data;//存放数据的Object数组
    public ArrayStack(int size)//根据参数初始化栈
    {
        if(size>0)
            maxSize = size;//初始化栈的大小
        data = new Object[maxSize];
        top = -1;//栈指针开始指向-1,即没有元素
    }
    public ArrayStack()//默认栈大小为10
    {
        this(10);
    }
    public boolean push(T myData)
    {
        if(isFull())
            throw new RuntimeException("您的栈已满,无法再加入新元素");
        top++;  //栈指针向后移动
        data[top] = myData;//数组对应位置插入数据
        return true;
    }
    public boolean isFull()
    {
        return top >= maxSize-1?true:false;//top指针大于等于maxSize-1时即为栈满
    }
    public boolean isEmpty()
    {
        return top == -1;//栈指针等于-1是表示没有数据,即为栈空
    }
    @SuppressWarnings("unchecked")
    public T pop()
    {
        if(isEmpty())
            throw new RuntimeException("您的栈已空,无法获取栈顶元素");
        return (T) data[top--];//弹出栈顶元素,并移动栈顶指针
    }
    @SuppressWarnings("unchecked")
    public T peek()
    {
        if(isEmpty())
            throw new RuntimeException("您的栈已空,无法查看栈顶元素");
        return (T) data[top];
    }
}

六,测试

import static java.lang.System.out;

public class TestArrayStack {

    public static void main(String[] args) {
        ArrayStack<String> ss = new ArrayStack<String>(5);
        ss.push("Java");
        ss.push("C");
        ss.push("C++");
        ss.push("Python");
        ss.push("C#");
        //ss.push("JavaScript");
        while(!ss.isEmpty())
        {
            out.println(ss.pop());
        }
        out.println(ss.peek());
        //out.println(ss.pop());

    }

}

运行结果:

C#
Python
C++
C
Java
Exception in thread "main" java.lang.RuntimeException: 您的栈已空,无法查看栈顶元素

从测试程序可以看出使用数组也是可以很好模拟栈操作的,除了大小无法动态扩展这个缺点外。

猜你喜欢

转载自blog.csdn.net/YIXIANG0234/article/details/79951063