定义
栈----------是一种特殊的线性表,只能在一端操作,有栈顶和栈底的概念
- 往栈中添加元素的操作,一般叫做
push
,也叫做入栈 - 从栈中移除元素的操作,一般叫做
pop
,也叫做出栈(注意:每次移除元素,只能移除栈顶元素,也叫做弹出栈顶元素)
栈,遵循后进先出的原则(即,后进栈的必须先出栈)英文叫做:Last In First Out(LIFO)
。下图是一个入栈和出栈的过程,可以看出,元素是一个一个push
进栈底,但是当出栈的时候,是从栈顶开始pop
。
注意:这里说的“栈”是一种数据结构的称呼,而“栈空间”是内存的概念。这两个是不同的概念,但是却有关系,这里先不提及。
栈的接口设计
右边就是一个栈的示意图。这样我们设计5个接口就可以了。
可不可以设计接口获得任意位置的元素呢?答案是:当然可以实现。但是,对于栈来说,只有栈顶元素我们可以看到,剩下的都是不可见的。因此,对于一个完美的栈,不应该让用户可以随意访问非栈顶元素。所以,别设计那些稀奇古怪的接口。
栈,其实就是线性表。因此完全可以利用已有的线性表结构。因此这里我们选择继承链表,然后实现栈的接口
- 返回栈的大小size(),判断栈是否为空isEmpty(),直接跟链表一样就行
public int size()
{
return size;
}
public boolean isEmpty()
{
return size == 0;
}
- 入栈操作
push(Type element)
,其实就是向线性表的尾部添加元素,那直接调用append(element)
就行了。
/**
* 入栈,也就是意味着向栈顶添加元素,类似于数组/链表的尾部添加元素
* @param element
*/
public void push(Type element)
{
append(element);
}
- 出栈操作
pop()
,也叫做弹出栈顶元素,那就相当于删除线性表的尾部元素并返回其元素值,所以可以直接调用remove(size - 1)
函数
/**
* 出栈,也就是弹出栈顶元素,那就是相当于删除数组/链表的尾部元素
* @return
*/
public Type pop(){
return remove(size - 1);
}
- 查看栈顶元素
top()
,那就相当于获得线性表的尾部元素值,可以直接调用get(size - 1)
函数
/**
* 获得栈顶元素,那就相当于获得数组/链表的尾部元素
* @return
*/
public Type top(){
return get(size - 1);
}
因此,整个栈的接口就这么几个,还是很简单的。
public class Stack<Type> extends LinkedList<Type> {
private int size;
public int size()
{
return size;
}
public boolean isEmpty()
{
return size == 0;
}
/**
* 入栈,也就是意味着向栈顶添加元素,类似于数组/链表的尾部添加元素
* @param element
*/
public void push(Type element)
{
append(element);
}
/**
* 出栈,也就是弹出栈顶元素,那就是相当于删除数组/链表的尾部元素
* @return
*/
public Type pop(){
return remove(size - 1);
}
/**
* 获得栈顶元素,那就相当于获得数组/链表的尾部元素
* @return
*/
public Type top(){
return get(size - 1);
}
}
那有人就会问了,栈都是用链表的数据结构在此封装的,栈(Stack)还有存在的必要吗?下面举例说明,栈的应用场景!
栈的应用场景
浏览器的前进与后退。
依次输入三个网址
现在停留在百度页面,没问题。当我点击后退时,
就会回到腾讯页面
当我再点击后退时,就会回到京东页面
这就叫先入后出,后入先出。因此浏览器的前进和后退键,是栈的一个经典应用。
还有一些经典的案例:一些app的撤销和恢复操作