当前位置:   article > 正文

递归法与迭代法实现树的遍历_与或树迭代

与或树迭代

递归法与迭代法实现树的遍历

递归法

首先树的遍历分为,前序遍历,中序遍历,后序遍历。

前序遍历: 对于当前结点,先对该结点进行操作,然后对他的左孩子进行操作,最后对他的右孩子进行操作。

中序遍历: 对于当前结点,先对该结点的左孩子进行操作,然后对该结点进行操作,最后对他的右孩子进行操作。

后序遍历: 对于当前结点,先对该结点的左结点进行操作,然后对右孩子进行操作,最后多该结点进行操作。

递归序:

其实对于树的遍历,递归法实现是比较简单的,只需要调整递归函数调用的位置即可,可是为什么递归能实现前序遍历,中序遍历和后序遍历呢?实际上是由递归时访问结点的顺序决定的。

public void recur(Node head){
    if(head == null) return;
    // 1
    recur(head.left);
    // 2
    recur(head.right);
    // 3
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

以上为递归遍历树时的通用代码,我们发现,对于当前结点head,在当前这个recur中,其实有三次都会返回到该结点,如注释1,这时当前结点为head结点;对于注释2,由于调用recur(head.left)结束,会再次返回到该结点;对于注释3,由于调用recur(head.right)结束,会再次返回到该结点,因此总共有三次会访问同一结点。

image-20211106101338970

对于该树,递归序为,1,2,4,4,4,2,5,5,5,2,1,3,6,6,6,3,7,7,7,3,1。

因此前序中序后序遍历,就是在分别在第一次第二次第三次到达该结点时进行操作,例如,前序遍历则是在1时,此时是第一次访问到该结点,因此先对该结点进行操作,就可以实现先序遍历。知道了递归序,递归实现树的三种遍历就很容易了,代码如下:

先序遍历:

public void preOrderRecur(Node head){
    if(head == null) return;
    System.out.print(head.val);
    recur(head.left);
    recur(head.right);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

中序遍历:

public void inOrderRecur(Node head){
    if(head == null) return;
    recur(head.left);
    System.out.print(head.val);
    recur(head.right);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

后序遍历:

public void posOrderRecur(Node head){
    if(head == null) return;
    recur(head.left);
    recur(head.right);
    System.out.print(head.val);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

迭代法:

两种方式是等价的,区别在于递归的时候隐式地维护了一个栈,而我们在迭代的时候需要显式地将这个栈模拟出来,其余的实现与细节都相同。

先序遍历迭代法

首先我们可以先定义一个栈,然后重复进行一下操作:

  1. 从栈中弹出当前结点
  2. 对当前结点进行处理
  3. 如果该结点有右结点或左结点,按先右后左的顺序压入栈中。
  4. 循环上述操作。
// 先序遍历!
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if (root == null){
            return res;
        }
        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        if(root != null){
            stack.push(root);
        }
        while(root != null && !stack.isEmpty() ){
            root = stack.pop();   //要注意弹出的不能为null,因此循环中需要判断stack不为空
            res.add(root.val);  // 弹出后进行操作。
            if(root.right != null){
                stack.push(root.right);
            }
            if(root.left != null){
                stack.push(root.left);
            }
        }
        return res;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

中序遍历迭代法:

  • 首先定义一个栈,将每棵子树的左边依次进栈
  • 依次弹出结点,对该结点进行操作
  • 对于弹出结点的右子树,重复上述操作。

即一直向左遍历,并且在遍历途中先将根结点和压入栈中,然后弹出左叶子结点后先判断是否其存在右结点(左结点在循环中已经判断),如果不存在则将其根结点进行弹出并输出,若存在,则继续向该右结点重复上述向左遍历的操作。

public static void inOrderUnRecur(Node root) {
    System.out.print("in-order: ");
    if (root != null) {
        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        while (!stack.isEmpty() || root != null) {
            if (root != null) {
                stack.push(root);
                root = root.left;
            } else {
                root = stack.pop();
                System.out.print(root.value + " ");
                root = root.right;
            }
        }
    }
    System.out.println();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

后序遍历迭代法

对于后序遍历,在树的知识点与算法中给出了一种遍历方法,但是可能会比较难理解,因此这里给出第二种方法。

首先由于根节点需要最后访问,而找到它的左右结点一定要先经过根结点,因此需要两个栈来维护访问顺序。栈1为访问所有结点的中介栈,栈2为最终所有结点的收集栈。我们要通过栈1实现压入栈2的顺序为头右左,这样在栈2中打印出来的顺序则可以变为左右头,实现后序遍历。

  • 从栈1弹出当前结点,放入栈2
  • 如果有左右结点,按先左后右的方式放入栈1中。
  • 循环上述操作直至所有结点压入栈2
  • 依次对栈2的结点进行操作。
public void posOrderUnrecur(TreeNode root){
    if(root!=null){
        Deque<TreeNode> s1 = new LinkedList<TreeNode>(); // 中介栈
        Deque<TreeNode> s1 = new LinkedList<TreeNode>(); // 收集栈
        s1.push(root);
        while(!s1.isEmpty()){
            root = s1.pop();
            s2.push(root);
            if(root.left != null){
                s1.push(root.left);   // 先放左
            }
            if(root.right != null){
                s1.push(root.right);  // 后方右 
            }
        }
        while(!s2.isEmpty()){
            System.out.print(s2.pop().val);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

如有错误,请大家指出,大家一起进步。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/274867
推荐阅读
相关标签
  

闽ICP备14008679号