线索化、遍历二叉树


// 线索化二叉树操作
public class ThreadedTree<T extends Comparable<? super T>> {
    public TreeNode<T> root;
    public TreeNode<T> pre = null;
    public ThreadedTree(TreeNode<T> root) {
        this.root = root;
    }
    public ThreadedTree(){}
    // 递归遍历
    private void preTree(TreeNode<T> node){
        if (node == null) return;
        System.out.println(node.data);
        preTree(node.left);
        preTree(node.right);
    }
    private void infixTree(TreeNode<T> node){
        if (node == null) return;
        infixTree(node.left);
        System.out.println(node.data);
        infixTree(node.right);
    }
    private void afterTree(TreeNode<T> node){
        if (node == null) return;
        if (!node.leftType){
            afterTree(node.left);
        }
        if (!node.rightType){
            afterTree(node.right);
        }
        System.out.println(node.data);
    }
    public void preTree(){
        this.preTree(root);
    }
    public void infixTree(){
        this.infixTree(root);
    }
    public void afterTree(){
        this.afterTree(root);
    }
    // add
    public ThreadedTree<T> add(T data){
        TreeNode<T> node = new TreeNode<>(data);
        if (this.root == null) this.root = node;
        else this.root.add(node);
        return this;
    }
    // 线索化
    private void preThreadedTree(TreeNode<T> node){
        if (node == null) return;
        if (node.left == null){
            node.leftType = true;
            node.left = pre;
        }
        if (pre != null && pre.right == null){
            pre.right = node;
            pre.rightType = true;
        }
        pre = node;
        if (!node.leftType) preThreadedTree(node.left);
        if (!node.rightType) preThreadedTree(node.right);
    }
    public void preThreadedTree(){
    	pre = null;
        this.preThreadedTree(root);
    }

    private void infixThreadedTree(TreeNode<T> node){
        if (node == null) return;
        infixThreadedTree(node.left);
        if (node.left == null){
            node.left = pre;
            node.leftType = true;
        }
        if (pre != null && pre.right == null){
            pre.right = node;
            pre.rightType = true;
        }
        pre = node;
        infixThreadedTree(node.right);
    }
    public void infixThreadedTree(){
        pre = null;
        this.infixThreadedTree(root);
    }

    private void afterThreadedTree(TreeNode<T> node){
        if (node == null) return;
        afterThreadedTree(node.left);
        afterThreadedTree(node.right);
        if (node.left == null){
            node.left = pre;
            node.leftType = true;
        }
        if (pre != null && pre.right == null){
            pre.right = node;
            pre.rightType = true;
        }
        pre = node;
    }
    public void afterThreadedTree(){
    	pre = null;
        this.afterThreadedTree(root);
    }

    // 清除线索
    private void clearThreaded(TreeNode<T> node){
        if (node == null) return;
        if (node.leftType){
            node.leftType = false;
            node.left = null;
        }else{
            clearThreaded(node.left);
        }
        if (node.rightType){
            node.rightType = false;
            node.right = null;
        }else{
            clearThreaded(node.right);
        }
    }
    public void clearThreaded(){
        this.clearThreaded(root);
    }
    // 线索化遍历
    public void preThreadedPrint(){
        if (root == null) return;
        TreeNode<T> node = root;
        while (node != null){
            while (!node.leftType){ // 递归当前子树的左节点,输出
                System.out.println(node.data);
                node = node.left;
            }
            System.out.println(node.data);
            node = node.right; // 该语句区别于中序线索遍历,可以通过画图理解
        }
    }
    public void infixThreadedPrint(){
        if (root == null) return;
        TreeNode<T> node = root;
        while (node != null){ // 遍历到当前子树的第一个节点
            while (!node.leftType){
                node = node.left;
            }
            System.out.println(node.data);
            while (node.rightType){ // 后驱节点,只管输出(因为当前节点的下一个就是后驱节点)
                node = node.right;
                System.out.println(node.data);
            }
            node = node.right;
            // 不写会死归,理解 当前树遍历(先找到第一个节点-也就是最左子节点,然后经过上面2次while操作后,返回到当前子树的第一个节点
            // 而 这步操作保证node 指向 当前子树的下一个节点)
        }
    }

    // 后续线索化遍历 仍采用递归方式(相较于常规遍历没有明显的提升)
        /*
         情况有4:
        1. 当前node就是根节点,没有父亲节点 打印结束 退出
        2. 当前节点是其父亲节点的左节点,且其父亲节点的左节点为空(node == node.parent.left && node.parent.rightType = false)
           或者 当前节点是其父亲节点的右节点(node == node.parent.right)
           则 节点变更为其父亲节点(node = node.parent)
        3. 当前节点是其父亲节点的左节点且其父亲节点的右节点不为空,则 node = 其父亲节点的右子树的第一个打印节点 
        */
    public void afterThreadedPrint(TreeNode<T> node){
        // 找到当前子树第一个节点
        while (true){ // 当当前节点为当前子树第一个输出的节点
            while (!node.leftType){
                node = node.left;
            }
            if (!node.rightType){
                node = node.right;
            }
            if (node.rightType && node.leftType || node.rightType && node.left == null){
                break;
            }
        }
        System.out.println(node.data); // 当前子树的第一个节点打印
        // 遍历节点直到不是右驱节点
        while (node.rightType){
            node = node.right;
            System.out.println(node.data);
        }

        // 按情况判断下一个节点=?,可以划分3种情况(树的根节点必定是最后一个打印),
        boolean condition2 = true; // 用于情况2 下一个节点为父节点,无需当做子树处理
        while (condition2){
            condition2 = false;
            if (node == root){

            }
            else if (node == node.parent.right || (node == node.parent.left && node.parent.rightType )){
                node = node.parent;
                System.out.println(node.data);
                condition2 = true;
            }
            else if(node.parent.right == null){ // 这种属于额外情况:父节点没有右子节点
                System.out.println(node.parent.data);
            }
            else if(node == node.parent.left && !node.parent.rightType){
                // 递归当前节点的父节点的右子节点
                afterThreadedPrint(node.parent.right);
            }

        }
    }
    public void afterThreadedPrint(){
        this.afterThreadedPrint(root);
    }
}

class TreeNode<T extends Comparable<? super T>>{
    public T data;
    public TreeNode<T> left;
    public TreeNode<T> right;
    public TreeNode<T> parent;
    public Boolean leftType = false;
    public Boolean rightType= false;
    public TreeNode(T data){
        this.data = data;
    }
    public void add(TreeNode<T> node){
        if (this.data.compareTo(node.data) == 0){
            System.out.println("value repeat");
        }else if (this.data.compareTo(node.data) > 0){
            if (this.left == null){
                this.left = node;
                node.parent = this;
                return;
            }
            this.left.add(node);
        }else if (this.data.compareTo(node.data) < 0){
            if (this.right == null){
                this.right = node;
                node.parent = this;
                return;
            }
            this.right.add(node);
        }
    }
}
class TestForThreadedTree{
    public static void main(String[] args) {
        ThreadedTree<Integer> tree = new ThreadedTree<>();
//        tree.add(30).add(20).add(13).add(18).add(10).add(25).add(12) ;
//        tree.add(12).add(13).add(14).add(15).add(19).add(16);
        tree.add(20).add(13).add(25).add(18).add(10).add(30).add(24);
        // 后续线索化、遍历测试
        tree.afterThreadedTree();
        tree.afterThreadedPrint();
        tree.clearThreaded();
        // 中序线索化、遍历测试
        tree.infixThreadedTree();
        tree.infixThreadedPrint();
        tree.clearThreaded();
        // 前序线索化、遍历测试
        tree.preThreadedTree();
        tree.preThreadedPrint();
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值