这是我参与更文挑战的第24天,活动详情查看:更文挑战
栈:先入后出的数据结构
在LIFO数据结构中,将首先处理添加到队列中的最新元素。与队列不同,栈是一个 LIFO 数据结构。通常,插入操作在栈中被称作入栈 push 。与队列类似,总是在堆栈的末尾添加一个新元素。但是,删除操作,退栈 pop ,将始终删除队列中相对于它的最后一个元素。
栈的简单实现
class MyStack {
private List<Integer> data;//存储元素
public MyStack() {
data = new ArrayList<>();
}
/** 入栈. */
public void push(int x) {
data.add(x);
}
/** 判空 */
public boolean isEmpty() {
return data.isEmpty();
}
/** 获取栈顶元素 */
public int top() {
return data.get(data.size() - 1);
}
/** 出栈 */
public boolean pop() {
if (isEmpty()) {
return false;
}
data.remove(data.size() - 1);
return true;
}
};
public class Main {
public static void main(String[] args) {
MyStack s = new MyStack();
s.push(1);
s.push(2);
s.push(3);
for (int i = 0; i < 4; ++i) {
if (!s.isEmpty()) {
System.out.println(s.top());
}
System.out.println(s.pop());
}
}
}
栈和深度优先搜索
与 BFS 类似,深度优先搜索(DFS)是用于在树/图中遍历/搜索的另一种重要算法。也可以在更抽象的场景中使用。
DFS中有三种遍历方式:先序遍历、中序遍历和后序遍历,三种遍历方式有一个共同的特性:除非到达最深的节点,否则不会回溯。
先序遍历
前序遍历首先访问根节点,然后遍历左子树,最后遍历右子树。
中序遍历
中序遍历是先遍历左子树,然后访问根节点,然后遍历右子树。
后序遍历
后序遍历是先遍历左子树,然后遍历右子树,最后访问树的根节点。
值得注意的是,当删除树中的节点时,删除过程将按照后序遍历的顺序进行。 也就是说,当你删除一个节点时,你将首先删除它的左节点和它的右边的节点,然后再删除节点本身。
递归方式深度优先搜索
当使用递归方式实现DFS时,似乎没有使用任何栈,实际上使用的系统提供的函数调用栈。
/*
* Return true if there is a path from cur to target.
*/
boolean DFS(Node cur, Node target, Set<Node> visited) {
return true if cur is target;
for (next : each neighbor of cur) {
if (next is not in visited) {
add next to visted;
return true if DFS(next, target, visited) == true;
}
}
return false;
}
显示使用栈结构实现深度优先搜索
递归方案的优点是更容易实现。但是,存在一个很大的缺点:当递归的深度太深时,容易遭受堆栈溢出。使用显示栈实现深度优先,可以规避这个问题。
/*
* Return true if there is a path from cur to target.
*/
boolean DFS(int root, int target) {
Set<Node> visited;
Stack<Node> s;
add root to s;
while (s is not empty) {
Node cur = the top element in s;
return true if cur is target;
for (Node next : the neighbors of cur) {
if (next is not in visited) {
add next to s;
add next to visited;
}
}
remove cur from s;
}
return false;
}