数据结构与算法(四)——双端栈的顺序存储结构

双端栈的定义:

是指将一个线性表的俩段当坐栈底分别进行入栈和出栈操作。

栈的顺序存储是很方便的,因为它只准栈顶进出元素,所以不存在线性表插入和删除时需要移动元素的问题。不过它有一一个很大的缺陷,就是必须事先确定数组存储空间大小,万一不够用了,就需要编程手段来扩展数组的容量,非常麻烦。对于一个栈,我们也只能尽量考虑周全,设计出合适大小的数组来处理,但对于两个相同类型的栈,我们却可以做到最大限度地利用其事先开辟的存储空间来进行操作。如果我们有两个相同类型的栈,我们为它们各自开辟了数组空间,极有可能是第一个栈已经满了,再进栈就溢出了,而另一个栈还有很多存储空间空闲。这又何必呢?我们完全可以用一一个数组来存储两个栈,下面我说一下我们的做法,如下图, 数组有两个端点,两个栈有两个栈底,让一个栈的栈底为数组的始端,即下标为0处,另一个栈为栈的末端,即下标为数组长度n-1处。这样,两个栈如果增加元素,就是两端点向中间延伸。
关键思路是:他们是从数组的俩端开始向中间靠拢,top1和top2是栈1和栈2的栈顶指针。如果他们俩不会相遇,那么这俩个栈就可以一直使用。进来元素以后,可以左边进一个,然后右边进一个,一直这样进栈。
左边的栈,也就是栈1,当栈1为空时,top1=-1.当top2=n时,即栈2为空。
如果栈2是空栈,栈1的top1=n-1时,栈1满了。反之,当栈1是空栈,栈2的top2=0时,栈2满。
不过上面的是极端情况,大多数还是当俩个栈见面是,栈满,即俩指针之间相差1时,top1 + 1==top2时为栈满。

双端栈的顺序存储结构ArrayStackEnd的定义:

下面看一下代码:

package DS01.动态数组;

import java.util.Iterator;

/*
* 双端栈
* */
public class ArrayStackDoubleEnd<E> implements Stack<E>{
    private static final int DEFAULT_SIZE=10;
    private E[] data;//创建一个数组
    private int leftTop;//定义栈1的指针,左栈顶
    private int rightTop;//定义栈2的指针,右栈顶

    public ArrayStackDoubleEnd(){//默认无参构造函数
        this(DEFAULT_SIZE);//使用this类内调用,调用一个参的构造函数
    }
    //创建一个指定的双端栈,传入一个参数
    public ArrayStackDoubleEnd(int capacity){
        data=(E[])(new Object[capacity]);//更新data。强转
        leftTop=-1;//默认左栈顶
        rightTop=data.length;//默认右栈顶
    }
    //获取左栈中有效元素个数
    public int getLeftSize(){
        return leftTop+1;
    }
    //获取右栈中有效元素个数
    public int getRightSize(){
        return data.length-rightTop;
    }
    //获取栈中所有元素的个数
    @Override
    public int getSize() {
        return getLeftSize()+getRightSize();
    }

    //判断左栈是否为空
    public boolean isLeftEmpty(){
        return leftTop==-1;
    }
    //判断右栈是否为空
    public boolean isRightEmpty(){
        return rightTop==data.length;
    }
    //判断栈是否为空
    @Override
    public boolean isEmpty() {
        return isLeftEmpty()&&isRightEmpty();
    }

    //在左栈进栈
    public void pushLeft(E e){
        //满了扩容
        if(leftTop+1==rightTop){
            resize(2*data.length);
        }
        leftTop++;
        data[leftTop]=e;
    }
    //在右栈进栈
    public void pushRight(E e){
        if(rightTop-1==leftTop){
            resize(2*data.length);
        }
        rightTop--;
        data[rightTop]=e;
    }
    private void resize(int newLen){
        E[] newData=(E[])(new Object[newLen]);
        //扩容和缩容时左边的复制
        for(int i=0;i<=leftTop;i++){
            newData[i]=data[i];
        }
        //扩容时右边的复制
        if(newData.length>data.length){
            for(int i=rightTop;i<data.length;i++){
                newData[i+data.length]=data[i];
            }
            rightTop=rightTop+data.length;
        }else{//缩容时右边的复制
            for(int i=rightTop;i<data.length;i++){
                newData[i-newData.length]=data[i];
            }
            rightTop=rightTop-newData.length;
        }

        data=newData;
    }
    //进栈元素e,哪边栈元素少进哪边
    @Override
    public void push(E e) {
        if(getLeftSize()<=getRightSize()){
            pushLeft(e);
        }else{
            pushRight(e);
        }
    }
//在左栈出栈
    public E popLeft(){
        if(isLeftEmpty()){
            throw new IllegalArgumentException("左栈为空");
        }
        E ret=data[leftTop--];

        if(getSize()<=data.length/4&&data.length/2>10){
            resize(data.length/2);
        }

        return ret;
    }
    //在右栈出栈
    public E popRight(){
        if(isRightEmpty()){
            throw new IllegalArgumentException("右栈为空");
        }
        E ret=data[rightTop++];
        if(getSize()<=data.length/4&&data.length/2>=10){
            resize(data.length/2);
        }
        return ret;
    }
     //进栈元素    规则:哪边栈元素多出哪边
    @Override
    public E pop() {
        if(getLeftSize()>=getRightSize()){
            return popLeft();
        }else{
            return popRight();
        }
    }

    public E peekLeft(){
        if(isLeftEmpty()){
            throw new IllegalArgumentException("左栈为空");
        }
        return data[leftTop];
    }
    public E peekRight(){
        if(isRightEmpty()){
            throw new IllegalArgumentException("右栈为空");
        }
        return data[rightTop];
    }
    @Override
    public E peek() { //获取栈顶  规则:哪边有效元素多,返回哪边的栈顶
        if(getLeftSize()>=getRightSize()){
            return peekLeft();
        }else{
            return peekRight();
        }
    }
//清空栈,置为默认构造函数。
    @Override
    public void clear() {
        data= (E[]) new Object[DEFAULT_SIZE];
        leftTop=-1;
        rightTop=data.length;
    }

    @Override
    public String toString() {
        StringBuilder sb=new StringBuilder();
        sb.append(String.format("ArrayStackDoubleEnd: %d/%d\n",getSize(),data.length));
        if(isLeftEmpty()){
            sb.append("left :bottom [] top");
        }else{
            sb.append("left :bottom [");
            for(int i=0;i<=leftTop;i++){
                sb.append(data[i]);
                if(i==leftTop){
                    sb.append("] top");
                }else{
                    sb.append(',');
                }
            }
        }
        sb.append('\n');
        if(isRightEmpty()){
            sb.append("right:top [] bootom\n");
        }else {
            sb.append("right:top [");
            for(int i=rightTop;i<data.length;i++){
                sb.append(data[i]);
                if(i==data.length-1){
                    sb.append("] bottom");
                }else{
                    sb.append(',');
                }
            }
        }
        return sb.toString();
    }

    @Override
    public Iterator<E> iterator() {
        return null;
    }
}

发布了48 篇原创文章 · 获赞 47 · 访问量 5247

猜你喜欢

转载自blog.csdn.net/weixin_45160969/article/details/103606686
今日推荐