Morris遍历

来源:互联网 发布:inapp软件 编辑:程序博客网 时间:2024/06/06 02:08

Morris算法,该算法的时间复杂度也是O(N),但是空间复杂度却能达到最优的O(1)。下面根据二叉树的三种遍历方式详细介绍Morris算法。

树的节点定义如下:

[java] view plain copy
  1. public class TreeNode {  
  2.     int val;  
  3.         TreeNode left;  
  4.         TreeNode right;  
  5.         TreeNode(int x) {   
  6.             val = x;   
  7.     }  
  8.     }  

一、中序遍历:

算法步骤: 

1. 如果当前节点的左子节点为空时,输出当前节点,并将当前节点置为该节点的右子节点;

2. 如果当前节点的左子节点不为空,找到当前节点左子树的最右节点(该节点为当前节点中序遍历的前驱节点);

2.1. 如果最右节点的右指针为空(right=null),将最右节点的右指针指向当前节点,当前节点置为其左子节点;

2.2. 如果最右节点的右指针不为空,将最右节点右指针重新置为空(恢复树的原状),输出当前节点,并将当前节点置为其右节点;

3. 重复1~2,直到当前节点为空。


下图显示了Morris算法中序遍历的过程。


Java实现如下:

[java] view plain copy
  1. public List<Integer> Morris_InOrder(TreeNode root) {  
  2.     List<Integer> res = new ArrayList<>();  
  3.     if(root == null)  
  4.         return res;  
  5.     TreeNode cur = root;  
  6.     while(cur != null) {  
  7.         if(cur.left == null) {  
  8.             res.add(cur.val);  
  9.             cur = cur.right;  
  10.         } else {  
  11.             TreeNode tmp = cur.left;  
  12.             while(tmp.right != null && tmp.right != cur)  
  13.                 tmp = tmp.right;  
  14.             if(tmp.right == null) {  
  15.                 tmp.right = cur;  //找到当前节点的前驱节点  
  16.                 cur = cur.left;  
  17.             } else {  
  18.                 res.add(cur.val);  
  19.                 tmp.right = null;  //恢复二叉树  
  20.                 cur = cur.right;  
  21.             }  
  22.         }  
  23.     }  
  24.     return res;  
  25. }  


二、前序遍历,前序遍历的基本思想和中序遍历很相似,只有输出顺序发生变化。

算法步骤:

1. 如果当前节点的左子节点为空时,输出当前节点,并将当前节点置为该节点的右子节点;

2. 如果当前节点的左子节点不为空,找到当前节点左子树的最右节点(该节点为当前节点中序遍历的前驱节点);

2.1. 如果最右节点的右指针为空(right=null),将最右节点的右指针指向当前节点,并输出当前节点(在此处输出),当前节点置为其左子节点;

2.2. 如果最右节点的右指针不为空,将最右节点右指针重新置为空(恢复树的原状),并将当前节点置为其右节点;

3. 重复1~2,直到当前节点为空。


下图显示了Morris算法前序遍历的过程:


Java实现如下:

[java] view plain copy
  1. public List<Integer> Morris_PreOrder(TreeNode root) {  
  2.     List<Integer> res = new ArrayList<>();  
  3.     if(root == null)  
  4.         return res;  
  5.     TreeNode cur = root;  
  6.     while(cur != null) {  
  7.         if(cur.left == null) {  
  8.             res.add(cur.val);  
  9.             cur = cur.right;  
  10.         } else {  
  11.             TreeNode tmp = cur.left;  
  12.             while(tmp.right != null && tmp.right != cur)  
  13.                 tmp = tmp.right;  
  14.             if(tmp.right == null) {  
  15.                 res.add(cur.val); //输出当前节点  
  16.                 tmp.right = cur;  //找到当前节点的前驱节点  
  17.                 cur = cur.left;  
  18.             } else {  
  19.                 tmp.right = null;  //恢复二叉树  
  20.                 cur = cur.right;  
  21.             }  
  22.         }  
  23.     }  
  24.     return res;  
  25. }  


、后序遍历:后序遍历较前两者比较麻烦,需要建立一个临时节点,并令该节点的左子节点为root,并且需要一个子过程,倒序输出某两个节点之间路径上的各个节点。

算法步骤:

1. 如果当前节点的左子节点为空时,则将其右子节点作为当前节点;

2. 如果当前节点的左子节点不为空,找到当前节点左子树的最右节点(该节点为当前节点中序遍历的前驱节点);

2.1. 如果最右节点的右指针为空(right=null),将最右节点的右指针指向当前节点,当前节点置为其左子节点;

2.2. 如果最右节点的右指针不为空,将最右节点右指针重新置为空(恢复树的原状),倒序输出从当前节点的左子节点到该最右节点路径上的所有节点,并将当前节点置为其右节点;

3. 重复1~2,直到当前节点为空。


下图显示了Morris算法后序遍历过程(其中虚线框内的节点为临时节点):


Java实现如下:

[java] view plain copy
  1. public List<Integer> Morris_PostOrder(TreeNode root) {  
  2.     List<Integer> res = new ArrayList<>();  
  3.     if(root == null)  
  4.         return res;  
  5.     TreeNode virNode = new TreeNode(-1);  //建立临时节点  
  6.     virNode.left = root;    //设置临时节点的左子节点为根节点  
  7.     TreeNode cur = virNode;  
  8.     while(cur != null) {  
  9.         if(cur.left == null) {  
  10.             cur = cur.right;  
  11.         } else {  
  12.             TreeNode tmp = cur.left;  
  13.             while(tmp.right != null && tmp.right != cur)  
  14.                 tmp = tmp.right;  
  15.             if(tmp.right == null) {  
  16.                 tmp.right = cur;  //找到当前节点的前驱节点  
  17.                 cur = cur.left;  
  18.             } else {  
  19.                 tmp.right = null;  //恢复二叉树  
  20.                 TreeNode t = cur.left;    
  21.                 List<Integer> tmpList = new ArrayList<>();  
  22.                 while(t != null) {  //倒序输出当前节点左子节点到当前节点前驱节点路径上的所有节点  
  23.                     tmpList.add(0, t.val);  
  24.                     t = t.right;  
  25.                 }  
  26.                 res.addAll(tmpList);  
  27.                 cur = cur.right;  
  28.             }  
  29.         }  
  30.     }  
  31.     return res;  
  32. }  
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 遇到恶意差评怎么办 银行账户被锁定怎么办 淘宝卖家说退货不全怎么办 买家旺旺被限制怎么办 淘宝支付不了了怎么办 手机图标变黑了怎么办 商品没有支付宝怎么办 金立s8热点打不开怎么办 淘宝店铺异常2怎么办 付款付错了怎么办 手机淘宝太卡怎么办 卖家不同意退货怎么办 游戏退出无响应怎么办 手机淘宝购物车打不开怎么办 淘宝店铺没有访客怎么办 淘宝店铺0流量怎么办 微信经常封号怎么办 网上拍卖堂违约怎么办 dnf4开组队制裁怎么办 红酒木塞丢了怎么办 红酒塞子进去了怎么办 淘金币即将过期怎么办 淘金币过期怎么办2018 换详情排名下降怎么办 长城宽带不用了怎么办 快递到了想退货怎么办 淘宝退货商家拒收怎么办 淘宝运费险失败怎么办 忘记购买运费险怎么办 咸鱼买家申请退款怎么办 熟猪肉有点变味怎么办 和领导意见不一致怎么办 骑手提前点送达怎么办 ubuntu安装报错怎么办 液相色谱两峰分不开怎么办 液相色谱柱老堵怎么办? 没有装usb驱动怎么办 ipad速度越来越慢怎么办 美萍管理软件打不开怎么办 小米4开机黑屏怎么办 小米电脑死机了怎么办