栈是一种后进先出的数据结构:见图(图片来自网络)
栈的应用:计算机撤销操作、符号匹配、计算代数式、函数调用、迷宫求解、数值转换、逆序输出等等。
下面将用demo来简单入门的了解栈这种数据结构:
首先创建一个接口,接口下有如下几个方法:
public interface Stack<E> {
//查找栈有多少个元素
int getSize();
//判断栈是否为空
boolean isEmpty();
//入栈
void push(E e);
//出栈
E pop();
//看栈顶的元素是谁
E peek();
}
接着定义一个基于动态数组来实现的栈,这个类实现以上定义的接口。这里的Array对象是之前写的一篇博客https://blog.csdn.net/qq_41723615/article/details/88413667里的底层动态Array类。由于篇幅长这里就不进行展示了。
不过需要对我们自己定义的Array添加以下两个方法,方便接下来的操作:
//调用size-1这个索引,取得最后一个元素(即栈顶的元素)
public E getLast(){
return get(size - 1);
}
//将0这个索引传进去,如果索引是0则会调用我们定义的Array类的get()方法,然后抛出异常
public E getFirst(){
return get(0);
}
public class ArrayStack<E> implements Stack<E> {
//定义一个Array成员变量
private Array<E> array;
//有参构造函数
public ArrayStack(int capacity){
//在构造一个array的时候,吧capacity容积传进入
array = new Array<>(capacity);
}
//无参构造,用于不知道这个栈能承载多大的容量
public ArrayStack(){
array = new Array<>();
}
@Override
public int getSize(){
return array.getSize();
}
@Override
public boolean isEmpty(){
return array.isEmpty();
}
public int getCapacity(){
return array.getCapacity();
}
@Override
public void push(E e){
//向数组的末尾,也就是栈顶添加一个元素,此操作调用了Array的size
//所以不需要考虑空间够不够的问题
array.addLast(e);
}
@Override
public E pop(){
//向数组的末尾,也就是栈顶取出一个元素,此操作调用了Array的size
//所以不需要考虑空间够不够的问题
return array.removeLast();
}
@Override
public E peek(){
//取得最后一个元素
return array.getLast();
}
@Override
//方便打印测试用
public String toString(){
//创建字符串
StringBuilder res = new StringBuilder();
res.append("Stack: ");
res.append('[');
//遍历栈中所有元素
for(int i = 0 ; i < array.getSize() ; i ++){
res.append(array.get(i));
//判断是否是最后一个元素
if(i != array.getSize() - 1)
res.append(", ");
}
res.append("] top");
return res.toString();
}
}
下面对栈的操作进行时间复杂度分析:
int getSize() | O(1) |
boolean isEmpty( | O(1) |
void push(E e) | O(1)均摊 |
E pop() | O(1)均摊 |
E peek() | O(1) |