关于学习王道数据结构所产生的各种疑问...

目前学习到现在所出现的问题如下

1.先序序列的线索二叉树构建这一节

基于先序序列进行构建线索二叉树时,向左先序化和向右先序化之前都需要进行是否是孩子标志条件判断,否则会出现栈溢出的异常,对于这一点,王道视频的数据结构中的示例代码中,只对向左先序化时进行了标志位的处理,并没有对向右先序化进行处理处理.这一点是我认为它的代码有漏洞的原因.

java版本的详细代码如下:

package com.wqc.tree.threadbinarytree;

/**
 * @author 高瞻远瞩
 * @version 1.0
 * @motto 算法并不可怕, 可怕的是你不敢面对它, 加油!别浮躁~冲击大厂!!!
 * 线索二叉树  叶子结点左指针指向前驱结点 右指针指向后继结点
 * n个结点的线索二叉树  空指针域有2n-(n-1) = n+1个
 * 明天实现基于先序实现线索二叉树
 */
public class ThreadBinaryTreeDemo {
    public static void main(String[] args) {
        ThreadBinaryTree threadBinaryTree = new ThreadBinaryTree();
        Node root = new Node(1, "tom");
        threadBinaryTree.setRoot(root);
        Node node1 = new Node(3, "lisa");
        Node node2 = new Node(6, "tony");
        Node node3 = new Node(8, "john");
        Node node4 = new Node(10, "marry");
        Node node5 = new Node(14, "jack");
        //生成二叉树
        root.setLeft(node1);
        root.setRight(node2);
        node1.setLeft(node3);
        node1.setRight(node4);
        node2.setLeft(node5);
        node1.setParent(root);//设置父结点
        node2.setParent(root);
        node3.setParent(node1);
        node4.setParent(node1);
        node5.setParent(node2);
        
        threadBinaryTree.preThreadBinaryTree();//先序遍历的结果 1 3 8 10 6 14
        //验证一下先序线索化是否成功
        System.out.println(node3.getLeft());//3
        System.out.println(node3.getRight());//10
        System.out.println(node4.getLeft());//8
        System.out.println(node4.getRight());//6
        System.out.println(node2.getRight());//14
        System.out.println(node5.getLeft());
        //输出6     node5节点本来是node2节点的左孩子  经过线索化后 确成为了node2节点前驱 相同的是 他们两个节点成为了前驱和后继的关系
        System.out.println(node5.getRight());//null
        System.out.println("递归方式进行先序遍历");
        threadBinaryTree.preOrder();
        System.out.println("非递归方式进行先序遍历");
        threadBinaryTree.preOrder2();
    }
}

class ThreadBinaryTree {
    private Node root;
    private Node pre; //在递归线索化时  pre总是保留前一个结点

    public void setRoot(Node root) {
        this.root = root;
    }

    /**
     * @param node 基于中序遍历构建线索二叉树
     */
    public void ThreadedNodes(Node node) {
        if (node == null) {//如果当前结点为null  不能线索化
            return;
        }
        if (node.getLeftType() != 1) {//在中序遍历中  此线索化的条件可以省略
            ThreadedNodes(node.getLeft());//线索化左子树
        }
        if (node.getLeft() == null) {
            node.setLeft(pre);//让当前结点左指针指向前驱结点
            node.setLeftType(1);
        }
        if (pre != null && pre.getRight() == null) {
            pre.setRight(node);//让pre的右指针指向后继结点
            pre.setRightType(1);
        }
        pre = node;
        if (node.getRightType() != 1) {
            ThreadedNodes(node.getRight());//线索化右子树
        }
    }

    //中序线索化二叉树的重载
    public void ThreadedNodes() {
        this.ThreadedNodes(root);
        pre.setRightType(1);
    }

    //递归方式中序遍历线索二叉树
    public void infixOrder() {
        if (root == null) {
            System.out.println("二叉树为空");
            return;
        }
        root.infixOrder();
    }

    //非递归方式中序遍历线索化二叉树
    public void infixOrder2() {
        Node node = root;
        while (node != null) {
            //先向左遍历到最左结点
            while (node.getLeftType() == 0) {
                node = node.getLeft();
            }
            //输出当前结点
            System.out.println(node);
            while (node.getRightType() == 1) {
                node = node.getRight();//让node指向它的后继结点  按照线索二叉树的次序
                if(node == null) return;
                System.out.println(node);//输出
            }
            node = node.getRight();//然后让node结点指向这个后继结点
        }
    }

    /**
     * 基于先序遍历构建线索二叉树
     * @param node
     */
    public void preThreadBinaryTree(Node node) {
        if (node == null) {//如果该结点已经线索化的话就返回
            return;
        }
        if (node.getLeft() == null) {
            node.setLeft(pre);//设置前驱结点
            node.setLeftType(1);
        }

        if (pre != null && pre.getRight() == null) {
            pre.setRight(node);
            pre.setRightType(1);
        }
        pre = node;
        //向左线索化
        if (node.getLeftType() != 1) {
            preThreadBinaryTree(node.getLeft());
        }
        //向右线索化
        if (node.getRightType() != 1) {
            preThreadBinaryTree(node.getRight());
        }
    }

    public void preThreadBinaryTree() {//先序线索二叉树的方法重载
        this.preThreadBinaryTree(root);
    }

    //递归方式的先序遍历线索二叉树
    public void preOrder() {
        if (root != null) {
            root.preOrder();
        } else {
            System.out.println("二叉树为空");
        }
    }

    //非递归方式的先序遍历线索二叉树
    public void preOrder2() {
        if (root == null) {
            System.out.println("二叉树为空");
            return;
        }
        Node node = root;
        while (node != null) {
            while (node.getLeftType() == 0) {
                System.out.println(node);//打印没有线索化的结点
                node = node.getLeft();
            }
            System.out.println(node);//退出时打印当前线索化的结点
            node = node.getRight();
        }
    }

    /**
     * 基于后序遍历构建线索二叉树
     * @param node
     */
    public void postThreadBinaryTree(Node node) {
        if (node == null) {
            return;
        }
        //向左线索化(前提是没有被线索化)
        if (node.getLeftType() == 0) {//在后续遍历中  此判断条件也可以省略
            postThreadBinaryTree(node.getLeft());
        }
        //向右线索化
        if (node.getRightType() == 0) {
            postThreadBinaryTree(node.getRight());
        }
        if (node.getLeft() == null) {
            node.setLeft(pre);
            node.setLeftType(1);
        }
        if (pre != null && pre.getRight() == null) {
            pre.setRight(node);
            pre.setRightType(1);
        }
        pre = node;
    }

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

    //递归方式后序遍历线索二叉树
    public void postOrder() {
        if (root != null) {
            root.postOrder();
        } else {
            System.out.println("二叉树为空");
        }
    }

    //非递归方式的后序遍历
    public void postOrder2() {
        Node node = root;
        if(node == null){
            System.out.println("二叉树为空");
            return;
        }
        Node pre = null;
        while(node.getLeftType() == 0){//先找到最左的线索化结点
            node = node.getLeft();
        }
        while(node != null){
            if(node.getRightType() == 1){//如果右结点是线索化结点
                System.out.println(node);//输出
                pre = node;
                node = node.getRight();
            }else{//如果不是线索化结点的话
                    if(node.getRight() == pre){//如果当前结点的右节点是上一个处理的结点的话
                        // 说明当前结点的左右子树都已经遍历结束
                        System.out.println(node);//输出当前结点
                        if(node == root){
                            return; //如果是根结点的话 直接跳出循环
                        }
                        pre = node;
                        node = node.getParent();
                    }else{//继续向右子树的左边遍历
                        node = node.getRight();
                        while(node != null && node.getLeftType() == 0){
                            node = node.getLeft();
                        }
                    }
            }
        }
    }
}

class Node {
    private int id;
    private String name;
    private Node left;
    private Node right;
    private int leftType;//默认为0 代表是指向左子树 1代表是前驱结点
    private int rightType;//默认为0 代表是指向右子树 1代表是后继结点
    private Node parent;//定义一个父结点 方便进行非递归的后序遍历

    public Node(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public Node getParent() {
        return parent;
    }

    public void setParent(Node parent) {
        this.parent = parent;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    public int getLeftType() {
        return leftType;
    }

    public void setLeftType(int leftType) {
        this.leftType = leftType;
    }

    public int getRightType() {
        return rightType;
    }

    public void setRightType(int rightType) {
        this.rightType = rightType;
    }

    //中序遍历
    public void infixOrder() {
        if (this.left != null && this.leftType == 0) {
            //左结点不为null  且 当前结点的左结点类型是左子树的话(即没有线索化的话)  才继续进行遍历
            this.left.infixOrder();
        }
        System.out.println(this);
        if (this.right != null && this.rightType == 0) {
            this.right.infixOrder();
        }
    }

    //先序遍历
    public void preOrder() {
        System.out.println(this);
        if (this.left != null && this.leftType == 0) {
            this.left.preOrder();
        }
        if (this.right != null && this.rightType == 0) {
            this.right.preOrder();
        }
    }

    //后续遍历
    public void postOrder() {
        if (this.left != null && this.leftType == 0) {
            this.left.postOrder();
        }
        if (this.right != null && this.rightType == 0) {
            this.right.postOrder();
        }
        System.out.println(this);
    }

    @Override
    public String toString() {
        return "Node{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

由于这个版本的数据结构是我最早学习的,所以示例代码基本上写的都有,当我今天再次学习c版本的时候,发现两者并无本质的差别,核心代码基本上都一模一样,我也懒得再写c版本的代码了.关键是c语言的语法太麻烦了.写起来太费时间了.我希望你们能理解我。
如下图:如果把167行和171行的条件判断任何一个去掉的话都会出现转圈问题的,最后也都会出现栈溢出的异常
在这里插入图片描述
这就是忽略向右线索化条件判断所出现的后果。。。。具体的实现过程可以自己debug一遍
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值