目录
1.栈(Stack)
-
栈是一种特殊的线性表,只能在一端进行操作。
往栈中添加元素的操作,一般叫做push,入栈。
从栈中移除元素的操作,一般叫做pop,出栈(只能移除栈顶元素,也叫做弹出栈顶元素)。
后进先出的原则:Last In First Out, LIFO
2.栈空间
注意:这里所说的栈
和内存中的栈空间
是两个不同的概念
1.进程内存映像
进程内存映像即用户进程的虚拟空间,一共包含了4个部分的内容:
- text代码段:是只读的,存放要执行的指令。
- data数据段:存放全局或静态变量。
- heap堆:运行时分配的内存(如用malloc,new函数申请的内存)
- statck栈:存放局部变量和函数返回地址
(所以说,调用一个方法/函数,即为这个方法开辟一个栈空间)
3.栈的接口设计
-
思考:栈的内部实现是否可以直接利用以前学过的数据结构呢?
因为栈的操作,主要就是对栈顶的元素进行出栈、入栈的操作。而动态数组和链表对尾部元素操作的时间复杂度都是
O(1)
。所以这两个都可以实现,且效率差不多。
4.实现:
4.1.直接继承ArrayList,复用其中的一些方法
- 1.代码实现
/**
* 描述:
* 栈,支持泛型
* @author txl
* @date 2021-11-19 23:40
*/
public class Stack<E> extends ArrayList<E> {
//直接继承自ArrayList
// public int size() {
// return 0;
// }
//直接继承自ArrayList
// public boolean isEmpty() {
// return false;
// }
/**
* 入栈
*/
public void push(E element) {
add(element);
}
/**
* 出栈
*/
public E pop() {
return remove(size-1);
}
/**
* 获取栈顶元素
*/
public E top() {
return get(size - 1);
}
}
-
2.直接继承的坏处:
扫描二维码关注公众号,回复: 13306601 查看本文章继承了ArrayList中的其他方法,这些方法根本不符合Stack只能从栈顶出栈入栈的属性。比如:
4.2.将ArrayList作为Stack的一个私有属性
- 1.代码实现:这样更合理一些
/**
* 描述:
* 栈,支持泛型
* @author txl
* @date 2021-11-19 23:40
*/
public class Stack<E>{
private List<E> list = new ArrayList<>();
public int size() {
return list.size();
}
public boolean isEmpty() {
return list.isEmpty();
}
/**
* 入栈
*/
public void push(E element) {
list.add(element);
}
/**
* 出栈
*/
public E pop() {
return list.remove(list.size()-1);
}
/**
* 获取栈顶元素
*/
public E top() {
return list.get(list.size() - 1);
}
}
5.Java官方提供的栈:java.util.Stack
-
继承自Vector:
public class Stack<E> extends Vector<E>{}
-
Vector和ArrayList的实现很相似,最大的区别在于其是一个线程安全的线性表:
public synchronized void trimToSize() { modCount++; int oldCapacity = elementData.length; if (elementCount < oldCapacity) { elementData = Arrays.copyOf(elementData, elementCount); } }
-
java.util.Stack中提供的方法:
其中peek()就是top():访问栈顶元素
6.栈的应用 - 浏览器的前进后退
1.浏览器的前进和后退是通过两个栈结构来实现的。
-
浏览器依次访问3个网站:入栈A
-
后退两次:栈A出栈两次,栈B入栈2次
-
在前进:栈A入栈,栈B出栈
-
访问一个新的网站:栈A入栈,栈B清空