中序遍历二叉树(递归、迭代、Morris算法)

中序遍历二叉树(递归、迭代、Morris算法)

三种算法时间、空间复杂度的比较:

算法时间复杂度空间复杂度
递归O(n)O(n)
迭代O(n)O(n)
MorrisO(n)O(1)

定义树节点

  public class  TreeNode {
      Integer data;
      TreeNode left;  //左节点
      TreeNode right;  //右节点
      //TreeNode parent;

      TreeNode(){
      }

      public TreeNode(Integer data) {
          this.data = data;
      }

      public TreeNode(Integer data, TreeNode left, TreeNode right) {
          this.data = data;
          this.left = left;
          this.right = right;
      }
  }

递归调用

递归算法:
中序遍历二叉树,根据左子树、根节点、右子树的顺寻实现二叉树的遍历

	public List<Integer> inorderTraversal1(TreeNode root) { // 中序遍历
	    List<Integer> list = new ArrayList<>();
	    inorder(root,list);
	    return list;
	}
	//递归调用实现中序遍历,时间与空间复杂度:O(n)
	public void inorder(TreeNode root,List<Integer> list){ 
	    if(root == null){
	        return;
	    }
	    inorder(root.left,list);
	    list.add(root.data);
	    inorder(root.right,list);
	}

递归调用算法完成中序遍历,时间与空间复杂度:O(n)

迭代

借助双端队列Deque实现

   //迭代实现中序遍历,时间与空间复杂度:O(n)
   public List<Integer> inorderTraversal2(TreeNode root){  

       List<Integer> list = new ArrayList<>();
       Deque<TreeNode> deque = new LinkedList<TreeNode>();

       while (root != null || !deque.isEmpty()){
           while (root != null){  //左子树
               deque.push(root);
               root = root.left;
           }
           root = deque.pop();
           list.add(root.data);  //根
           root = root.right;  //右子树
       }
       return list;
   }

迭代实现中序遍历,时间与空间复杂度:O(n)

Morris算法

Morris 遍历算法整体步骤如下(假设当前遍历到的节点为 x):

1.如果 x 无左孩子,先将 x 的值加入答案数组,再访问 x 的右孩子,即 x=x.right。
2.如果 x 有左孩子,则找到 x 左子树上最右的节点(即左子树中序遍历的最后一个节点,x 在中序遍历中的前驱节点),我们记为 predecessor。根据 predecessor 的右孩子是否为空,进行如下操作。

  • 如果 predecessor 的右孩子为空,则将其右孩子指向 x,然后访问 x 的左孩子,即 x=x.left。
  • 如果 predecessor 的右孩子不为空,则此时其右孩子指向 x,说明我们已经遍历完 x 的左子树,我们将 predecessor 的右孩子置空,将 x 的值加入答案数组,然后访问 x 的右孩子,即 x=x.right。

3.重复上述操作,直至访问完整棵树。

  //Morris 实现中序遍历,时间复杂度:O(n),空间复杂度:O(1)
  public List<Integer> inorderTraversal3(TreeNode root) {  
      List<Integer> arrayList = new ArrayList<>();
      TreeNode predecessor = null;

      while (root != null) {
          if (root.left != null) {
              // predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
              predecessor = root.left;
              while (predecessor.right != null && predecessor.right != root) {
                  predecessor = predecessor.right;
              }

              // 让 predecessor 的右指针指向 root,继续遍历左子树
              if (predecessor.right == null) {
                  predecessor.right = root;
                  root = root.left;
              }
              // 说明左子树已经访问完了,我们需要断开链接
              else {
                  arrayList.add(root.data);
                  predecessor.right = null;
                  root = root.right;
              }
          }
          // 如果没有左孩子,则直接访问右孩子
          else {
              arrayList.add(root.data);
              root = root.right;
          }
      }
      return arrayList;
  }

Morris 实现中序遍历时,时间复杂度:O(n),空间复杂度:O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值