只需消耗O(1)空间遍历二叉树
背景:在《数据结构》中,二叉树是有两个左右结点的,并且没有父结点,因此我们在使用递归遍历、非递归遍历都需要消耗O(logN)的栈空间,只是使用递归时消耗的是方法栈罢了,而消耗这一部分只是为了记住父节点,以达到我们的目的。
但是有没有存在一种方式可以利用树本身来记住,这就是要介绍的morris的遍历。利用的是二叉树的叶子结点游离的指针。
假设这样的步骤:
1、假设当前子树的头节点为h,让h的左子树中最右节点的right指针指向h,然后h的左子树继续步骤1的处理过程,直到遇到某一个节点记为node,开始进入步骤2
2、从node开始通过每个节点的right指针进行移动,并依次打印,假设移动到节点为cur。对每一个cur节点的左子树中最右节点是否指向cur
(1)如果是,让cur节点的左子树中最右节点的right指针指向空,也就是把步骤1的调整后再逐渐调整回来,然后打印cur
(2)如果不是,以cur为头的子树重回步骤1执行
假设你可以想象吧,简单的说就是连线后把线删除,遇到新的右子树就再继续这样做,连线删线...
但是呢?
我写的并不顺利,因为被重复调用陷入进去了,都在考虑怎么在移动中使用连线删线,完全没法写下去了。。。因为这是最直观的思路,但是已经陷入了局部了
翻看了左程云的《程序员面试经典》,简直觉得大神就是牛,我真的完全没有想到,他采用了循环,然后对于当前的节点和处理操作进行控制,简直简单容易理解
public void morrisIn(Node head){
if (head==null)
return;
Node cur1=head;
Node cur2=null;
while (cur1!=null){
cur2=cur1.left; //得到左子树,以便获得是否是连线还是断开
if (cur2!=null){
while (cur2.right!=null && cur2.right!=cur1){
cur2=cur2.right;
}
if (cur2.right==null){ //连线
cur2.right=cur1;
cur1=cur1.left; //往左移动当前的结点
continue; //经典的控制,个人看法,简直不要太牛逼
}else { //拆开线
cur2.right=null;
}
}
System.out.print(cur1.val+" ");
cur1=cur1.right; //更换当前的结点
}
System.out.println();
}
至少我写不出这样的,太难想了,有没有大佬有更好地想法或者是思路,一起交流

浙公网安备 33010602011771号