21 线索二叉树 (前序、中序、后序线索化二叉树及遍历)

线索二叉树

1. 基本介绍

  1. n 个结点的二叉链表中含有 n+1 【公式 2n-(n-1)=n+1】 个空指针域。利用二叉链表中的空指针域,存放指向该结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")。
  2. 这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树( Threaded BinaryTree )。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
  3. 一个结点的前一个结点,称为前驱结点。
  4. 一个结点的后一个结点,称为后继结点。

2. 代码实现(前序、中序、后序线索化二叉树及遍历)

public class ThreadTreeDemo {
    public static void main(String[] args) {
        //构建二叉树
        Node node1 = new Node(1);
        Node node2 = new Node(2);
        Node node3 = new Node(3);
        Node node4 = new Node(4);
        Node node5 = new Node(5);
        Node node6 = new Node(6);
        Node node7 = new Node(7);
        Node node8 = new Node(8);
        node1.setLChildNode(node2);
        node1.setRChildNode(node3);
        node2.setLChildNode(node4);
        node3.setLChildNode(node5);
        node3.setRChildNode(node6);
        node5.setLChildNode(node7);
        node5.setRChildNode(node8);
        ThreadTree threadTree = new ThreadTree(node1);

        // 构建前序线索二叉树
        //threadTree.preThreadTree();
        // 遍历前序线索二叉树
        //threadTree.preThreadTreeList();

        // 构建中序线索二叉树
        //threadTree.infixThreadTree();
        // 遍历中序线索二叉树
        //threadTree.infixThreadTreeList();

        // 构建后序线索二叉树
        //threadTree.postThreadTree();


    }
}

class ThreadTree {
    // 定义根节点
    private Node root;
    // 定义前驱节点
    private Node pre;

    public ThreadTree(Node root) {
        this.root = root;
    }


    // 重载先序线索化二叉树
    public void preThreadTree() {
        preThreadTree(root);
    }

    // 重载中序线索化二叉树
    public void infixThreadTree() {
        infixThreadTree(root);
    }

    // 重载后续线索化二叉树
    public void postThreadTree() {
        postThreadTree(root);
    }

    // 先序线索化二叉树
    private void preThreadTree(Node node) {
        if (node == null) {
            return;
        }
        // 找到最左边的节点,将其前驱赋值给其左孩子
        if (node.getLChildNode() == null) {
            node.setLChildNode(pre);
            node.setLTag(1);
        }
        // 如果前驱节点不为空并且其没有右孩子,则将当前节点作为其后继
        if (pre != null && pre.getRChildNode() == null) {
            pre.setRChildNode(node);
            pre.setRTag(1);
        }
        // pre 后移
        pre = node;

        // 左右指针指向的不是线索才能继续递归
        if (node.getLTag() == 0) {
            preThreadTree(node.getLChildNode());
        }
        if (node.getRTag() == 0) {
            preThreadTree(node.getRChildNode());
        }
    }

    // 中序线索化二叉树
    private void infixThreadTree(Node node) {
        if (node == null) {
            return;
        }
        // 左指针指向的不是线索才能继续递归,递归左子树
        if (node.getLTag() == 0) {
            infixThreadTree(node.getLChildNode());
        }
        // 找到最左边的节点,将其前驱赋值给其左孩子指针
        if (node.getLChildNode() == null) {
            node.setLChildNode(pre);
            node.setLTag(1);
        }
        // 如果前驱节点不为空并且其没有右孩子,则将当前节点作为其后继
        if (pre != null && pre.getRChildNode() == null) {
            pre.setRChildNode(node);
            pre.setRTag(1);
        }
        // pre 后移
        pre = node;
        // 右指针指向的不是线索才能继续递归,递归右子树
        if (node.getRTag() == 0) {
            infixThreadTree(node.getRChildNode());
        }
    }

    // 后续线索化二叉树
    private void postThreadTree(Node node) {

        if (node == null) {
            return;
        }
        // 递归左子树
        if (node.getLTag() == 0) {
            postThreadTree(node.getLChildNode());
        }
        // 递归右子树
        if (node.getRTag() == 0) {
            postThreadTree(node.getRChildNode());
        }
        // 找到最左边的节点,将其前驱赋值给其左孩子指针
        if (node.getLChildNode() == null) {
            node.setLChildNode(pre);
            node.setLTag(1);
        }
        // 如果前驱节点不为空并且其没有右孩子,则将当前节点作为其后继
        if (pre != null && pre.getRChildNode() == null) {
            pre.setRChildNode(node);
            pre.setRTag(1);
        }
        // pre 后移
        pre = node;
    }

    // 遍历先序线索二叉树
    public void preThreadTreeList() {
        if (root != null) {
            Node temp = root;
            while (temp != null) {
                while (temp.getLTag() == 0) {
                    System.out.println(temp);
                    temp = temp.getLChildNode();
                }
                System.out.println(temp);
                temp = temp.getRChildNode();
            }
        }
    }

   // 遍历中序线索二叉树
   public void infixThreadTreeList() {
        if (root != null) {
            Node temp = root;
            while (temp != null) {
                while (temp.getLTag() == 0) {
                    temp = temp.getLChildNode();
                }
                System.out.println(temp);
                while (temp.getRTag() == 1) {
                    temp = temp.getRChildNode();
                    System.out.println(temp);
                }
                temp = temp.getRChildNode();
            }
        }
   }

   // 遍历后序线索二叉树
    // public void postThreadTreeList() {}
}


class Node {
    private int data;
    private Node LChildNode;
    private Node RChildNode;
    // 标记:0 为指向孩子;1 为指向前驱或后继
    private int LTag;
    private int RTag;

    public Node(int data) {
        this.data = data;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public Node getLChildNode() {
        return LChildNode;
    }

    public void setLChildNode(Node LChildNode) {
        this.LChildNode = LChildNode;
    }

    public Node getRChildNode() {
        return RChildNode;
    }

    public void setRChildNode(Node RChildNode) {
        this.RChildNode = RChildNode;
    }

    public int getLTag() {
        return LTag;
    }

    public void setLTag(int LTag) {
        this.LTag = LTag;
    }

    public int getRTag() {
        return RTag;
    }

    public void setRTag(int RTag) {
        this.RTag = RTag;
    }

    @Override
    public String toString() {
        return "Node{" +
                "data=" + data +
                '}';
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值