栈的顺序存储结构
栈的定义:
栈是限定仅在表尾进行插入和删除操作的线性表
- 我们吧允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom)
- 不含任何元素的栈称为空栈
- 栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构
- 栈本身时一个线性表,其数据元素具有线性关系,只不过它是一种特殊的线性表而已
- 定义中说的是在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底
- 栈的插入操作,叫做进栈,也称压栈、入栈
- 栈的删除错做,叫做出栈、弹栈
Stack的定义 | 含义 | @reruen返回值 | @parm参数 |
---|---|---|---|
int getSize | 获取栈中元素的个数 | 栈中的元素个数 | |
boolean isEmpty() | 判断 栈是否为空 | 是否为空的boolean值 | |
void push(E e) | 进栈一个元素 | e 即将进栈的元素 | |
E pop() | 弹栈一个元素 | 当前出栈的元素 | |
E peek() | 获取当前栈顶(不移除) | 当前栈顶的元素 不弹栈 | |
void clear | 清空 |
栈的顺序存储结构ArrayStack的定义
ArrayStack的定义 | 含义 | @reruen返回值 | @parm参数 |
---|---|---|---|
ArrayStack() | 创建一个默认的大小的栈(顺序表 | ||
ArrayStack(int capacity) | 创建一个容量为指定capacity大小的栈(顺序表) | ||
getSize() | 获取栈中元素的个数 | list.getSize() | |
isEmpty () | 判断 栈是否为空 | list.isEmpty | |
push(E e) | 进栈元素e | list.addLast(e) | |
E pop() | 出栈元素e | list.removeLast() | |
E peek() | 查找当前栈顶(不移除) | list.getLast() | |
clear() | 清空栈 | list.clear() |
public boolean equals(Object obj){
return list.equals(obj);
}
在栈中(Object obj)中obj是栈,而 list.equals(obj)中list是顺序表,这里直接拿栈和顺序表去比较了。
obj不能直接获取list,因为子类对象指向父类引用(多态)
多态的情况下不能获取子类的特有行为,只能访问父类
public boolean equals(Object obj){
if(obj==null){ //先比较空
return fasle;
}
if(obj==this){ //在比较自己
return true;
}
if(obj instanceof ArrayStack){ //你属于一个栈
ArrayStack stack=(ArrayStack)obj; //强转obj成栈
return list.equals(stack.list); //list标志栈当前的list stack.list:传进来的栈内部的list
}
return false;
}
public String toString() {
StringBuilder sb=new StringBuilder();//StringBuilder没锁,快
//每次都显示现在的有效个数,和最大容量
sb.append("ArrayStack: size="+getSize()+",capacity="+list.getCapacity()+"\n");
if(isEmpty()){
sb.append("[]");
}else{
sb.append('[');
for(int i=0;i<getSize();i++){ //list.size不再list的内部,不能访问
sb.append(list.get(i));
if(i==getSize()-1){ //到了最后一个时
sb.append(']');
}else{
sb.append(',');//用","拼接的时候会产生好多字符串,所以改用','
}
}
}
return sb.toString();
}
public class Main{
public static void main(String[] args){
ArrayStack<Integer> stack=new ArrayStack<Integer>();
for(int i=0;i<=10;i++){
stack.push(i); //元素进栈
}
System.out.println(stack); // [1,2,3,4,5,6,7,8,9,10]
}
for(int i=1;i<=5;i++){
System.out.println(stack.pop()); //元素出栈
}
System.out.println(stack); // [1,2,3,4,5]
ArrayStack<Integer> stack2=new ArrayStack<Integer>();
stack2.push(1); //创建另外一个栈
stack2.push(2);
stack2.push(3);
stack2.push(4);
stack2.push(5);
System.out.println(stack.equals(stack2)); // true
}
双端栈的顺序存储结构
定义:
是指将一个线性表的俩端当作栈底分别进行入栈和出栈的操作
不能用ArrayList的实现,因为ArrayList里面只有一个size来表示栈顶,而双端栈ArrayStackDoubeEnd有俩个栈顶。
重新定义
public class ArrayStackDoubleEnd<E> implements stack<E>{
enum Direction{ //枚举 ,定义一个类型叫Direction只能存储俩个值LEFT,RIGHT
LEFT,RIGHT;
}
private E[] data ; //用于存储数据的容器
private int leftTop; //左端栈的栈顶 开始在-1
private int rightTop; //右端的栈顶 开始在data.length
private static int DEFAUL_SIZE=10; //默认容量大小为10
public ArrayStackDoubleEnd() {
this(DEFAULT_SIZE);
}
public ArrayStackDoubleEnd(int capacity) {
data=(E[]) new Object[capacity];
leftTop=-1;
rightTop=data.length;
}
}
ArrayStackDoubeEnd的定义 | 含义 | @reruen返回值 @parm参数 |
---|---|---|
ArrayStackDoubleEnd() | 创建一个默认的大小的栈 | |
ArrayStackDoubleEnd(int capacity) | 创建一个容量为指定capacity大小的栈 | |
void push(Direction dir,E e) | 向指定的端口进栈元素 | |
E pop(Direction dir) | 从指定得到端口出栈元素 | |
E Peek(Direction dir) | 从指定的端口获取元素 | |
getSIize(Direction dir) | 获取指定端口栈的元素个数 | |
isEmpty(Direction dir) | 判断指定端口的栈是否为空 | |
clear(Directon dir) | 清空指定端口的栈 | |
getSize() | 获取左端栈和右端栈元素的总和 | getSize(Direction.LEFT)+getSize(Direction.RIGHT) |
isEmpty () | 判断 左端栈和右端栈是否全为空 | isEmpty(Direction.LEFT)&&isEmpty(Direction.RIGHT) |
push(E e) | 哪端少哪端进栈元素e | |
push(E e) | 哪端少哪端进栈元素e | |
E pop() | 哪端多弹栈哪端元素e | pop(Direction.LEFT) |
E pop() | 哪端多弹栈哪端元素e | pop(Direction.RIGHT) |
E peek() | 哪端多获取哪端当前栈顶元素(一样多,默认右) | peek(Direction.LEFT) |
E peek() | 哪端多获取哪端当前栈顶元素(一样多,默认右) | peek(Direction.RIGHT) |
clear() | 左右俩端都清空 | |
clear() | 左右俩端都清空 |
判断栈是否已满
private boolean isFull() {
return leftTop+1==rightTop;
}
向指定的端口进栈元素
public void push(Direction dir,E e) {
if(isFull()) {
resize(data.length*2); //扩容
}
if(dir==Direction.LEFT) {
data[++leftTop]=e; //放在左端
}else {
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];
}
int index=data.length-1;//右端复制
int i;
for( i=newData.length-1;i>newData.length-data.length+rightTop;i--) {//双指针
newData[i]=data[index--];
}
rightTop=i+1;
data=newData;
}
从指定得到端口出栈元素
public E pop(Direction dir) {
if(dir==Direction.LEFT) { //左端
if(leftTop==-1) { //抛异常
throw new IllegalArgumentException("左端栈为空:");
}
if(getSize()<=data.length/1&&data.length>DEFAULT_SIZE) {
resize(data.length/2); //缩容
}
return data[leftTop--]; //元素被取走。top--:往前退一格
}else {
if(rightTop==data.length) { //右端,抛异常
throw new IllegalArgumentException("右端栈为空:");
}
if(getSize()<=data.length/1&&data.length>DEFAULT_SIZE) {
resize(data.length/2); //缩容
}
return data[rightTop++]; 元素被取走。top++:往后退一格
}
}
从指定得到端口获取栈顶元素
public E peek(Direction dir) {
if(dir==Direction.LEFT) {
if(leftTop==-1) {
throw new IllegalArgumentException("左端栈为空:");
}
return data[leftTop];
}else {
if(rightTop==data.length) {
throw new IllegalArgumentException("右端栈为空:");
}
return data[rightTop];
}
}
获取指定端口栈的元素个数
public int getSize(Direction dir) {
if(dir==Direction.LEFT) {
return leftTop+1; 左边个数
}else {
return data.length-rightTop ;右边的个数
}
}
判断指定端口是否为空
public boolean isEmpty(Direction dir) {
if(dir==Direction.LEFT) {
return leftTop==-1;
}else {
return rightTop==data.length;
}
}
清空指定端口的栈
public void clean(Direction dir) {
if(dir==Direction.LEFT) {
leftTop=-1;
}else {
rightTop=data.length;
}
}
拼接
public String toString() {
StringBuilder sb=new StringBuilder();//StringBuilder没锁,快
//每次都显示现在的有效个数,和最大容量
sb.append("ArrayStack: size="+getSize()+",capacity="+data.length+"\n");
if(isEmpty()){ //双端空
sb.append("[]");
}else{
sb.append('[');
int count=0;
for(int i=0;i<=leftTop;i++) { //左边的遍历
sb.append(data[i]);
count++; //每进一个元素记录一次
if(count==getSize()) { //当count=有效数字的时候
sb.append(']');
}else {
sb.append(',');
}
}
for(int i=rightTop;i<data.length;i++) { //右边的遍历
sb.append(data[i]);
count++;
if(count==getSize()) {
sb.append(']');
}else {
sb.append(',');
}
}
}
return super.toString();
}
比较
public boolean equals(Object obj) { //纯粹比较俩个双端栈的内容
if(obj==null){
return false;
}
if(obj==this){
return true;
}
if(obj instanceof ArrayStackDoubleEnd) { //属于一个栈
ArrayStackDoubleEnd<E> stack=(ArrayStackDoubleEnd) obj;//创建一个传入栈stack,并进行强转
if(getSize()==stack.getSize()) {
ArrayList<E> list1=new ArrayList<E>(getSize());
ArrayList<E> list2=new ArrayList<E>(getSize());
for(int i=0;i<=leftTop;i++) { //将左边的数拼接到当前栈的左部分
list1.addLast(data[i]);
}
for(int i=rightTop;i<data.length;i++) { //拼接当前栈的右部分
list1.addLast(data[i]);
}
for(int i=0;i<=stack.leftTop;i++) { //拼接传入栈的左部分
list2.addLast(stack.data[i]);
}
for(int i=stack.rightTop;i<stack.data.length;i++) { //拼接传入栈的右部分
list2.addLast(stack.data[i]);
}
return list1.equals(list2);
}
}
return false;
}
枚举的概述:
枚举是在一定范围内取值,并且这个值必须是枚举类型中的任意一个,并且只能有一个
特点:
1.必须在规定范围内取值
2.这个值只能取一个
3.这个值可以是规定范围内的任意一个枚举的本质就是一个Java类