我们遍历树节点时,经常会去使用递归算法,空间复杂度是树的高度,因为系统会帮我们去进行压栈操作,而Morris算法可以达到时间复杂度O(N),空间复杂度O(1)的
本代码观看左神算法,记录一下code,以便日后复习,有需要的小伙伴copy哦(写的不好,勿喷,小白一枚)
树节点类:
class TreeNode{
public int value;
public TreeNode left;
public TreeNode right;
public TreeNode(int value){
this.value = value;
this.left = null;
this.right = null;
}
}
正常的Morris遍历:
//Morris遍历
public static void Morris(TreeNode root){
if(root == null) return;
TreeNode cur = root;
while(cur != null){
TreeNode MostRight = cur.left;
if(MostRight != null){
//寻找左子树最右节点
while(MostRight.right != null && MostRight.right != cur){
MostRight = MostRight.right;
}
//找到了左子树最右节点
if(MostRight.right == null){ //第一次找最右节点(cur被访问的第一次)
System.out.print(cur.value + " ");
MostRight.right = cur;
cur = cur.left;
continue;
}else{ //第二次找最右节点(cur被访问的第二次)
MostRight.right = null;
}
}
System.out.print(cur.value + " ");
cur = cur.right;
}
}
Morris先序遍历:(被访问两次的节点)第一次访问到节点时,就打印,仅访问一次的节点,访问就打印
//Morris先序遍历
public static void MorrisPre(TreeNode root){
if(root == null) return;
TreeNode cur = root;
while(cur != null){
TreeNode MostRight = cur.left;
if(MostRight != null){
//寻找左子树最右节点
while(MostRight.right != null && MostRight.right != cur){
MostRight = MostRight.right;
}
//找到了左子树最右节点
if(MostRight.right == null){ //第一次找最右节点(cur被访问的第一次)
System.out.print(cur.value + " ");
MostRight.right = cur;
cur = cur.left;
continue;
}else{ //第二次找最右节点(cur被访问的第二次)
MostRight.right = null;
}
}else{
System.out.print(cur.value + " ");
}
cur = cur.right;
}
}
Morris中序遍历:(被访问两次的节点)第二次访问到节点时,就打印,仅访问一次的节点,访问就打印
//Morris中序遍历
public static void MorrisIn(TreeNode root){
if(root == null) return;
TreeNode cur = root;
while(cur != null){
TreeNode MostRight = cur.left;
if(MostRight != null){
//寻找左子树最右节点
while(MostRight.right != null && MostRight.right != cur){
MostRight = MostRight.right;
}
//找到了左子树最右节点
if(MostRight.right == null){ //第一次找最右节点
MostRight.right = cur;
cur = cur.left;
continue;
}else{
System.out.print(cur.value + " "); //第二次找最右节点
MostRight.right = null;
}
}else{
System.out.print(cur.value + " ");
}
cur = cur.right;
}
}
Morris后续遍历:只要是第一次访问节点,不用管,第二次访问节点时,打印当前节点的左子树的右边界的逆序
//Morris后序遍历(第二次访问左子树最右节点,打印当前节点左子树右边界的逆序)
public static void MorrisPost(TreeNode root){
if(root == null) return;
TreeNode cur = root;
while(cur != null){
TreeNode MostRight = cur.left;
if(MostRight != null){
while(MostRight.right != null && MostRight.right != cur){
MostRight = MostRight.right;
}
if(MostRight.right == null){
MostRight.right = cur;
cur = cur.left;
continue;
}else{
MostRight.right = null;
printEdge(cur.left);
}
}
cur = cur.right;
}
printEdge(root);
}
//打印当前节点的右边界(右节点组成的链表)
private static void printEdge(TreeNode x) {
TreeNode head = reverseEdge(x);
TreeNode cur = head;
while(cur != null){
System.out.print(cur.value + " ");
cur = cur.right;
}
reverseEdge(head);
}
//正常链表的反转
private static TreeNode reverseEdge(TreeNode head) {
TreeNode pre = null;
TreeNode next;
while(head != null){
next = head.right;
head.right = pre;
pre = head;
head = next;
}
return pre;
}