• 28-线索化二叉树


    1. 引入

    2. 基本介绍

    • n 个结点的二叉链表中含有 n+1 个空指针域
    • 利用二叉链表中的空指针域,存放指向该结点在某种遍历次序下前驱和后继结点的指针(这种附加的指针称为"线索")
      • 一个结点的前一个结点,称为“前驱结点”
      • 一个结点的后一个结点,称为“后继结点”
    • 这种加上了线索的二叉链表称为线索链表,相应的二叉树称为“线索(Threaded) 二叉树”。根据线索性质的不同,线索二叉树又可分为:
      • 前序线索二叉树
      • 中序线索二叉树
      • 后序线索二叉树

    3. 案例

    3.1 中序线索化二叉树

    3.2 遍历线索化二叉树

    4. 代码实现

    public class ThreadedBinaryTreeDemo {
        public static void main(String[] args) {
            ThreadedBinaryTree tree = new ThreadedBinaryTree();
            Node root = new Node(1);
            Node node3 = new Node(3);
            Node node6 = new Node(6);
            Node node8 = new Node(8);
            Node node10 = new Node(10);
            Node node14 = new Node(14);
            root.left = node3;
            root.right = node6;
            node3.left = node8;
            node3.right = node10;
            node6.left = node14;
            tree.root = root;
            tree.midThreadedNodes();
            System.out.println("node10-left: " + node10.left);
            System.out.println("node10-right: " + node10.right);
            tree.midOrderThreadedBiTree();
        }
    }
    
    // 实现了线索化功能的二叉树
    class ThreadedBinaryTree{
        public Node root;
        /*
         * 为了实现线索化, 需要创建 1 个指向当前结点的前驱结点的引用
         * 在递归进行线索化时, preNode 总是指向前一个结点
         */
        public Node preNode;
    
        public void midThreadedNodes() {
            midThreadedNodes(root);
        }
    
        // 中序线索化
        public void midThreadedNodes(Node node) {
            if (node == null) return;
            // 1. 线索化左子树
            midThreadedNodes(node.left);
    
            // 2. 线索化当前结点
            // 2.1 处理当前结点的前驱结点
            if (node.left == null) {
                // 修改当前结点的左指针类型
                node.leftType = 1;
                // 当前结点的左指针指向中序遍历时的前驱结点
                node.left = preNode;
            }
            // 2.2 处理(上一个结点的)后继结点
            if (preNode != null && preNode.right == null) {
                // 修改上一个结点的右指针类型
                preNode.rightType = 1;
                // 上一个结点的右指针指向当前结点
                preNode.right = node;
            }
            // 2.3* 每处理完一个结点, 便让当前结点成为下一个待处理结点的前驱结点
            preNode = node;
    
            // 3. 线索化右子树
            midThreadedNodes(node.right);
        }
    
        // 中序遍历
        public void midOrderThreadedBiTree() {
            // 存储当前遍历的结点
            Node node = root;
            while (node != null) {
                // leftType = 1说明该结点是按照线索化处理后的有效结点
                while (node.leftType == 0) // 第一个找到的是[8]
                    node = node.left;
                // 退出循环则说明找到了leftType = 1的结点, 打印当前结点即可
                System.out.println(node);
    
                // 如果当前结点的右指针指向后继结点, 就输出
                while (node.rightType == 1) {
                    node = node.right;
                    System.out.println(node);
                }
                node = node.right;
            }
        }
    
    }
    
    class Node {
        public int no;
        public Node left;
        public Node right;
        /*
         * leftType = 0, 表示指向左子树
         *          = 1, 表示指向前驱结点
         * rightType = 0, 表示指向右子树
         *           = 1, 表示指向后继结点
         */
        public int leftType;
        public int rightType;
    
        public Node(int no) {
            this.no = no;
        }
    
        @Override
        public String toString() {
            return "[no=" + no + "]";
        }
    }
    

    [待补充] 前序线索化二叉树和后序线索化二叉树及有关遍历

  • 相关阅读:
    MongoDB
    Mac下将Python2.7改为Python3
    Kafka
    Server 基础概念 备忘
    应用内支付
    Sign in with apple
    Linux三剑客grep/sed/awk
    React-Native中使用到的一些JS特性
    Date Picker控件:
    Picker View控件:
  • 原文地址:https://www.cnblogs.com/liujiaqi1101/p/12327932.html
Copyright © 2020-2023  润新知