双端栈
双端栈定义:是指将一个线性表的两端当做栈底分别进行进栈出栈操作。
双端栈既然也是栈,那就可以直接实现接口Stack,其操作与栈是一样的,只是相当于有两个栈,可以定义左栈和右栈,对于内部方法,分别讨论左右两个栈情况,再综合两者实现。
/*
双端栈
*/
public class ArrayStackDoubleEnd<E> implements Stack<E>{
private static final int DEFAULT_SIZE=10;
private E[] data; //底层还是用动态数组实现
private int leftTop; //左栈顶
private int rightTop; //右栈顶
//构造函数
public ArrayStackDoubleEnd(){
this(DEFAULT_SIZE); //调用一个参的构造函数
}
//创建一个指定的指定的双端栈
public ArrayStackDoubleEnd(int capacity){
data = (E[]) (new Object[capacity]);
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(isLeftEmpty()){
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;
}
//按字符串返回
public String toString(){
StringBuilder sb=new StringBuilder();
sb.append(String.format("ArrayStrackDoubleEnd: %d/%d\n",getSize(),data.length));
if(isLeftEmpty()){
sb.append("left :bottom [] top \n");
}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 [] bottom \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();
}
}
一样的,写完一个结构可以自己做过测试,这里不赘述了。