深度搜索,如果用递归的话,层数过多会报错,用栈写的话,可能会很复杂。
所以用链表反而会很方便。
这种链表,第一个节点不指向第二个节点。
反而是下一个节点指向它的上面。
可以说,它和别的链表反着来。
那链表里面储存什么呢?储存的是每一次深度搜索时的变量,参数等。
我们可以定义一个数据结构,里面存储的是这次深搜的变量。
为什么子节点指向父节点呢,而父节点不指向子节点呢?因为当搜索完成,返回上一层时,直接cur = cur.paret就可以了,而大多数语言都有回收机制,只要子节点没有人用它,就会自动回收。
以二叉树深度搜索为例。
二叉树的结构,和它的内容:
//二叉树结构
class Node{
int val;
Node left,right,parent;
public Node(Node parent,int val,boolean left){
this.val = val;
this.parent = parent;
if(parent != null){
if(left)
parent.left = this;
else
parent.right = this;
}
}
}
//二叉树内容
Node root = new Node(null,1,true);
Node cur = new Node(root, 2,true);
new Node(root,3,false);
new Node(cur,4,true);
new Node(cur,5,false);
cur = root.right;
new Node(cur,6,true);
new Node(cur,7,false);
二叉树内容图示
然后我们开始做链表。
链表的定义:
class DfsNode{
DfsNode parent;
Node treeNode;//当前搜索到的 二叉树节点
int visitNum = 0;//正在遍历它的第几个孩子,0是要遍历左孩子,1是要遍历右孩子,2是遍历完了
public DfsNode(DfsNode parent,Node cur){
this.parent = parent;
this.treeNode = cur;
}
}
}
深度遍历的代码:
//第一个节点
DfsNode curr = new DfsNode(null,root);
while(true){
//如果还没遍历过,就打印它的值
if(curr.visitNum == 0)
System.out.println(curr.treeNode.val);
if(curr.visitNum == 0){
//遍历左节点
curr.visitNum++;
curr = new DfsNode(curr,curr.treeNode.left);
}else if(curr.visitNum == 1){
//遍历右节点
curr.visitNum++;
curr = new DfsNode(curr,curr.treeNode.right);
}else{
//遍历完了左和右
if(curr.parent == null) //如果没没有上一层,就跳出循环
break;
curr = curr.parent; //否则返回它的上一层,继续搜索
}
if(curr.treeNode == null){
//如果没有左右孩子,则返回上一层
curr = curr.parent;
}
}
}
/*输出数据
1
2
4
5
3
6
7
*/
我个人觉得,这种相对于递归会复杂一些。
不过这个案例举得其实不太行,因为二叉树它想深度遍历,还有更简单的办法,而二叉树的栈遍历,似乎也比这个简单。
Stack<Node> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
Node now = stack.pop();
if(now == null)
continue;
stack.push(now.left);
stack.push(now.right);
System.out.println(now.val);
}
虽然如此,但是如果应用在复杂场景,它应该会显得凸出一些。
(钻进地缝)