Java常见算法(五)【二叉树:morris遍历】

二叉树遍历-线索二叉树(Morris)

https://www.bilibili.com/video/BV1Jv411A7Ty?p=31
在这里插入图片描述

1、前序遍历-线索二叉树

https://www.bilibili.com/video/BV1Jv411A7Ty?p=32

 //1、前序-线索二叉树:根   左  右
    public static void morrisPre(TreeNode cur){
    
    
        if(cur==null){
    
    
            return;
        }
        TreeNode mosRight=null;
        while(cur!=null){
    
    
            mosRight=cur.left;
            if(mosRight!=null){
    
    
                while (mosRight.right!=null&&mosRight.right!=cur){
    
    
                    mosRight=mosRight.right;
                }
                if(mosRight.right==null){
    
    //1、重点:建立线索指针
                    mosRight.right=cur;
                    System.out.println(cur.val);
                    cur=cur.left; //指针左移,并继续找前区节点
                    continue;
                }else{
    
    //2、重点:mosRight.right=cur; 删除线索指针
                    mosRight.right=null;
                }
            }else{
    
    
                System.out.println(cur.val);
            }
            cur=cur.right;
        }
    }

2、中序遍历-线索二叉树(常用)

https://www.bilibili.com/video/BV1Jv411A7Ty?p=32
在这里插入图片描述
中序遍历是比较容易也是常用的方法,从左向右看,其实中序遍历就是一个二叉树的投影。
左子树最右侧的节点就是右侧节点的前驱节点,比如找 1 的前驱节点就是 7 。

    //2、中序-线索二叉树:左  根  右
    public static void morrisMid(TreeNode cur){
    
    
        if(cur==null){
    
    
            return;
        }
        TreeNode mosRight=null;
        while(cur!=null){
    
    
            mosRight=cur.left;
            if(mosRight!=null){
    
    
                while (mosRight.right!=null&&mosRight.right!=cur){
    
    
                    mosRight=mosRight.right;
                }
                if(mosRight.right==null){
    
    //1、重点:建立线索指针
                    mosRight.right=cur;
                    cur=cur.left; //指针左移,并继续找前区节点
                    continue;
                }else{
    
    //2、重点:mosRight.right=cur; 删除线索指针
                    mosRight.right=null;
                }
            }else{
    
    

            }
            System.out.println(cur.val);
            cur=cur.right;
        }
    }

3、后序遍历-线索二叉树(不推荐)

https://www.bilibili.com/video/BV1Jv411A7Ty?p=33

 //3、后序-线索二叉树:左   右  根
    // Morris后续遍历:只关注有左子树的节点,第二次遍历到的时候逆序打印左子树的右边界,最后再单独打印整棵树的右边界
    public static void morrisPost(TreeNode root){
    
    
        if(root == null){
    
    
            return;
        }
        TreeNode current = root;
        TreeNode mostRight = null;
        while(current != null){
    
    
            mostRight = current.left;
            // current 有左子树时,就要进行Morris遍历
            if(mostRight != null){
    
    
                while(mostRight.right != null && mostRight.right != current){
    
    
                    // 找到左子树的最右子节点mostRight
                    mostRight = mostRight.right;
                }
                // mosrRight找到了,说明是第一次来到cur
                if(mostRight.right == null){
    
    
                    mostRight.right = current;
                    current = current.left;
                    continue;
                }else{
    
    
                    mostRight.right = null;
                    // 第二次到达该节点,就逆序打印其左子树的右边界
                    printEdge(current.left);
                }
            }
            // 无左子树 或者左子树已经遍历完了就遍历右子树
            current = current.right;
        }
        // 打印整棵树的右边界
        printEdge(root);
    }

        // 逆序打印node节点的右边界,单链表反转的形式实现逆序
    public static void printEdge(TreeNode node){
    
    
        TreeNode tail = reverseEdge(node);
        TreeNode current = tail;  // 记录下,用于后面的反转
        while(current != null){
    
    
            System.out.print(current.val + " ");
            current = current.right;
        }
        // 打印完成,还需要将树还原,再反转一次
        reverseEdge(tail);
    }

    public static TreeNode reverseEdge(TreeNode node){
    
    
        TreeNode pre = null;
        TreeNode next = null;
        while(node != null){
    
    
            next = node.right;
            node.right = pre;
            pre = node;
            node = next;
        }
        return pre;
    }

实验源码:

package com.example.rabbitmq;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

@SpringBootTest
/*
    二叉树遍历-Morris线索二叉树
 */
class SuanfaApplicationTests19 {
    
    

    //定义一个二叉树
    static class TreeNode{
    
    
        public int val;
        public TreeNode left;
        public TreeNode right;
        public int deep;//深度
        public TreeNode(){
    
    }
        public TreeNode(int val){
    
    this.val=val;}
        public TreeNode(int val,TreeNode left,TreeNode right){
    
    
            this.val=val;
            this.left=left;
            this.right=right;
        }
    }

    //1、前序-线索二叉树:根   左  右
    public static void morrisPre(TreeNode cur){
    
    
        if(cur==null){
    
    
            return;
        }
        TreeNode mosRight=null;
        while(cur!=null){
    
    
            mosRight=cur.left;
            if(mosRight!=null){
    
    
                while (mosRight.right!=null&&mosRight.right!=cur){
    
    
                    mosRight=mosRight.right;
                }
                if(mosRight.right==null){
    
    //1、重点:建立线索指针
                    mosRight.right=cur;
                    System.out.println(cur.val);
                    cur=cur.left; //指针左移,并继续找前区节点
                    continue;
                }else{
    
    //2、重点:mosRight.right=cur; 删除线索指针
                    mosRight.right=null;
                }
            }else{
    
    
                System.out.println(cur.val);
            }
            cur=cur.right;
        }
    }

    //2、中序-线索二叉树:左  根  右
    public static void morrisMid(TreeNode cur){
    
    
        if(cur==null){
    
    
            return;
        }
        TreeNode mosRight=null;
        while(cur!=null){
    
    
            mosRight=cur.left;
            if(mosRight!=null){
    
    
                while (mosRight.right!=null&&mosRight.right!=cur){
    
    
                    mosRight=mosRight.right;
                }
                if(mosRight.right==null){
    
    //1、重点:建立线索指针
                    mosRight.right=cur;
                    cur=cur.left; //指针左移,并继续找前区节点
                    continue;
                }else{
    
    //2、重点:mosRight.right=cur; 删除线索指针
                    mosRight.right=null;
                }
            }else{
    
    

            }
            System.out.println(cur.val);
            cur=cur.right;
        }
    }

    //3、后序-线索二叉树:左   右  根
    // Morris后续遍历:只关注有左子树的节点,第二次遍历到的时候逆序打印左子树的右边界,最后再单独打印整棵树的右边界
    public static void morrisPost(TreeNode root){
    
    
        if(root == null){
    
    
            return;
        }
        TreeNode current = root;
        TreeNode mostRight = null;
        while(current != null){
    
    
            mostRight = current.left;
            // current 有左子树时,就要进行Morris遍历
            if(mostRight != null){
    
    
                while(mostRight.right != null && mostRight.right != current){
    
    
                    // 找到左子树的最右子节点mostRight
                    mostRight = mostRight.right;
                }
                // mosrRight找到了,说明是第一次来到cur
                if(mostRight.right == null){
    
    
                    mostRight.right = current;
                    current = current.left;
                    continue;
                }else{
    
    
                    mostRight.right = null;
                    // 第二次到达该节点,就逆序打印其左子树的右边界
                    printEdge(current.left);
                }
            }
            // 无左子树 或者左子树已经遍历完了就遍历右子树
            current = current.right;
        }
        // 打印整棵树的右边界
        printEdge(root);
    }

        // 逆序打印node节点的右边界,单链表反转的形式实现逆序
    public static void printEdge(TreeNode node){
    
    
        TreeNode tail = reverseEdge(node);
        TreeNode current = tail;  // 记录下,用于后面的反转
        while(current != null){
    
    
            System.out.print(current.val + " ");
            current = current.right;
        }
        // 打印完成,还需要将树还原,再反转一次
        reverseEdge(tail);
    }

    public static TreeNode reverseEdge(TreeNode node){
    
    
        TreeNode pre = null;
        TreeNode next = null;
        while(node != null){
    
    
            next = node.right;
            node.right = pre;
            pre = node;
            node = next;
        }
        return pre;
    }



    @Test
    public void sf0(){
    
    
        //构造一个二叉树
        TreeNode node7=new TreeNode(7,null,null);
        TreeNode node6=new TreeNode(6,null,null);
        TreeNode node5=new TreeNode(5,node6,node7);
        TreeNode node4=new TreeNode(4,null,null);
        TreeNode node3=new TreeNode(3,null,null);
        TreeNode node2=new TreeNode(2,node4,node5);
        TreeNode node1=new TreeNode(1,node2,node3);

        System.out.println("-------前序遍历-线索二叉树------");
        morrisPre(node1);

        System.out.println("-------中序遍历-线索二叉树------");
        morrisMid(node1);

        System.out.println("-------后序遍历-线索二叉树------");
        morrisPost(node1);
    }

}

结果:

-------前序遍历-线索二叉树------
1
2
4
5
6
7
3
-------中序遍历-线索二叉树------
4
2
6
5
7
1
3
-------后序遍历-线索二叉树------
4
6
7
5
2
3
1 

猜你喜欢

转载自blog.csdn.net/YL3126/article/details/121529184
今日推荐