栈——链栈和数组栈(Java)

  栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。栈最大的特点就是先进后出

上面是栈存取数据的示意图,栈主要分为两种结构:基于数组实现的数组栈和基于链表实现的链栈,总的来说都是栈结构,实现的都是栈的基本操作,而栈的操作需要具体的结构去实现,因此数组栈和链栈都是实现的栈接口,我们先定义一个栈接口:

interface Stack {
    public abstract void push(int e);  //入栈操作
    public abstract int pop();    //弹栈
    public abstract int length();  //有效元素个数
    public abstract boolean isEmpty(); //判空操作
}

数组栈/顺序栈:由数组实现的,但是不提供角标的访问,只在栈顶进行操作。

/*
基于数组实现的栈
*/
class ArrayStack implements Stack{
    private static int DEFAULT_SIZE=10; //默认容量
    private int top;    //栈顶指针
    private int[] data; //存储元素的容器用数组存储
    //创建一个栈使用默认容量
    public ArrayStack(){
        this(DEFAULT_SIZE);
    }
    //创建一个栈使用用户指定容量capacity
    public ArrayStack(int capacity){
        super();
        this.top=-1; //初始化栈顶元素
        this.data=new int[capacity]; //初始化容量
    }
    //入栈一个元素e
    public void push(int e){ 
        if(top==data.length-1){  //入栈前要判满,如果栈顶指针达到容量最大,表示无法入栈
            System.out.println("栈已满!无法入栈元素");
        }
        data[++top]=e; //否则先将栈顶指针先向上移动一个,将元素添加到该指针位置
    }
      //出栈一个元素
    public int pop(){
        if(isEmpty()){ //出栈前先判空
            System.out.println("栈已空!无法出栈元素");  //栈内为空,没有元素
            return -1;//特殊含义 表示错误
        }
        return data[top--];  //栈不为空,先将元素弹栈,再将栈顶指针下移
    }
    //判断栈是否为空
    public boolean isEmpty(){  
        return this.top==-1; //如果当前栈顶元素为空,为true否则为false
    }
    //获取有效元素的个数
    public int length(){
        return this.top+1;  //获取当前栈顶指针加一,因为是用数组实现的
    }
    public String toString(){  //以字符串形式打印当前栈内元素
        StringBuilder sb=new StringBuilder(); 
        sb.append('[');
        for(int i=0;i<=top;i++){
            sb.append(data[i]);
            if(i==top)
                return sb.append(']').toString();
            sb.append(',');
            sb.append(' ');
        }
        return "[]";
    }
    //获取当前栈的总容量
    public int getCapacity(){
        return data.length;  //总容量就是数组的大小
    }
}

链栈,是由链表实现的,链表由一系列结点(链表中每一个元素称为结点)组成,每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。这里是链栈结构,则存取完全可以根据栈结构对头结点进行操作。

class LinkedStack extends Stack{   //单向链表
    private Node head;      //链表的头结点
    private int size;      //链表长度
    public LinkedStack(){ 
        this.head=new Node();
        this.size=0;
    }
 
     //加入结点是不用判满的,因为链表没有容量限制
    public void push(int e){  //在头结点后添加一个新的元素结点
        Node n=new Node(); //新创建一个结点
        n.data=e;  //将创建的结点中的数据域用来存放传入的元素
        n.next=head.next; //将创建的结点中的指针域用来存放当前头结点的下一个结点的地址
        head.next=n;  //然后将新创建的结点的地址赋给头结点的指针域
        //head.next=new Node(e,head.next); 上面三行代码可简化成这一句
        size++; //链表长度加一
    }
    public int pop(){   //元素出栈
        if(isEmpty()){  //出栈判空
            System.out.println("栈已空!不能出栈元素!");
            return -1;
        }
        Node n=head.next;  //元素不为空,将头元素的下一个元素提取出来
        head.next=n.next;    //将头元素下一个结点的下一个结点的地址赋给头元素的指针域
        n.next=null;   //将头元素的下一个结点的指针域置为null,与原链表断离
        size--;      //相应的链表长度减一
        return n.data;   //将删除的结点的数据返回
    }
    public int length(){  //获取链表的长度
        return size;   //直接返回size,因为这个变量记录了链表的长度
    }
    public boolean isEmpty(){  //判空
        return size==0&&head.next==null;  //如果链表长度为0和头结点的后面没有其他结点,则为空
    }
    public String toString(){  //获取链表得字符串形式输出
        if(isEmpty()){
            return "[]";
        }
        Node p=head.next;  //定义一个结点变量存放头结点的下一个结点的地址
        StringBuilder sb=new StringBuilder();
        sb.append('[');
        while(true){
            sb.append(p.data); //将该结点的数据域添加到字符串中
            if(p.next==null){
                sb.append(']');
                break;
            }else{
                sb.append(", ");
                p=p.next;  //再将下一个结点的地址赋给当前结点变量
            }
        }
        return sb.toString();
    }

    //内部类:在类里面定义的类
    private class Node{   //结点类
        int data;   //数据域
        Node next;   //指针域
        Node(){
            this(0,null);
        }
        Node(int data,Node next){  //带参的构造函数
            this.data=data;   
            this.next=next;
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章