前序、中序、后序二叉树的线索化及遍历

先看一个问题
将数列{1,3,6,8,10,14}构建成一颗二叉树
如图
问题分析:
1.当我们对上边的二叉树进行中序遍历时,数列为{8,3,10,1,14,6}
2.但是6,8,10,14这几个节点的左右指针并没有完全利用上
3.如果我们希望充分的利用各个节点的左右指针,让各个节点可以指向自己的前后节点怎么办
前序、中序、后序二叉树的线索化及遍历_第1张图片解决方法-线索二叉树
线索二叉树基本介绍
1.n个节点的二叉链表中含有n+1公式2n-(n-1)=n+1个空指针域。利用二叉链表中的空指针域,存放指向节点在某种遍历次序下的前驱和后继节点的指针(这种附加的指针被称为线索)
一个节点有两个指向 n个节点需要n-1个线连接
即空指针域2n-(n-1)
2.这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树,根据线索的性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种
3.一个节点的前一个节点,称为前驱节点
4.一个节点的后一个节点,称为后继节点
说明:当线索化二叉树后,node节点的属性left和right,有如下情况
1.left指向的左子树,也可能是指向的前驱节点
2.right指向的是右子树,也可能是后继节点

遍历线索化二叉树
说明:对前面的中序线索化的二叉树,进行遍历
分析:因为线索化后,各个节点的指向有变化,因此原来的遍历方式不能使用,需要使用新的方式遍历线索化二叉树,各个节点可以通过线性方式遍历,因此无需使用递归方式,这样也提高了遍历的效率,遍历的次序应当和中序遍历保持一致

首先前序、中序、后序的二叉树的线索化的方式大致相同的
只是由于遍历方式的不同,递归左右节点和处理当前节点的位置不同
具体可以看着代码对比着自己画出的线索化的二叉树来进行分析

线索化遍历的时候可能有些问题,就是定义的存储当前指针的赋值问题
中序遍历和前序遍历较好理解
后序遍历还需要一个新的parent来解决该问题,下边代码中也有体现,
后序的规则如下:
1.若节点是二叉树的根,则其后继节点为空
2.若节点是其双亲的右孩子,或是其双亲的左孩子,且其双亲没有右子树,则其后继节点为其双亲节点
3.若节点是其双亲的左孩子,且其双亲有右子树,则其节点为双亲右子树上,按后序遍历列出的第一个节点
话不多说,我们下边的代码也是基于上图的二叉树来进行的,代码中也有一些遍历撒撒的,可以挑重点阅读。
测试代码二叉树的创建方式我还是手动创建的,就不放在这里了

//定义BinaryTree
//实现了线索化功能的二叉树
class BinaryTree{
    private DataNode root;
    //为了实现线索化,需要定义一个指向当前节点的前驱节点的指针
    private DataNode pre=null;

    public void setPre(DataNode pre) {
        this.pre = pre;
    }

    public DataNode getPre() {
        return pre;
    }

    public void setRoot(DataNode root) {
        this.root = root;
    }
    public  void threadedNodes(){
        threadedNodes(this.root);
    }
    public  void threadedPostNodes(){
        threadedPostNodes(this.root);
    }
    public  void threadPreNodes(){
        threadedPreNodes(this.root);
    }

    //前序线索遍历二叉树的方法
    public void threadedPreList(){
        //定义节点,存储当前遍历的节点,初始为root;
        DataNode node=root;
        while(node!=null){
            while (node.getLeftType()==0){
                System.out.println(node);
                node=node.getLeft();
            }
            System.out.println(node);
            node=node.getRight();
        }
    }
    //中序遍历线索化二叉树的方法
    public void threadMidList(){
        //定义一个节点,存储当前遍历的节点,初始时为root
        DataNode node=root;
        while(node!=null){
            //找到lefttype==1的节点,第一个就是8节点
            //后面随着遍历node会变化,因为当lefttype==1时,说明当前节点是按照线索化处理后的有效节点
            while (node.getLeftType()==0){
                node=node.getLeft();
            }
            System.out.println(node);
            //如果当前节点的右指针指的是后继节点
            while (node.getRightType()==1){
                //获取当前节点的后继节点
                node=node.getRight();
                System.out.println(node);
            }
            //替换这个遍历的节点
            node=node.getRight();

        }
    }
    //后序遍历线索化二叉树的方法

    /**
     * 1.若节点是二叉树的根,则其后继节点为空
     * 2.若节点是其双亲的右孩子,或是其双亲的左孩子,且其双亲没有右子树,则其后继节点为其双亲节点
     * 3.若节点是其双亲的左孩子,且其双亲有右子树,则其节点为双亲右子树上,按后序遍历列出的第一个节点
     */
    public void ThreadedPostList(){
        //定义一个节点存储遍历的节点,初始化时间为root
        DataNode node=root;
        while(node!=null){
            while(node.getLeftType()==0){
                node=node.getLeft();
            }
            System.out.println(node);
            //处理后继节点
            while(node.getRightType()==1){
                node=node.getRight();
                System.out.println(node);
            }
            if(node==root){
                node=null;
            }else if(node==node.getParent().getRight() || (node==node.getParent().getLeft() && node.getParent().getRight()==null)){
                node=node.getParent();
            }else if(node==node.getParent().getLeft() && node.getParent().getRight()!=null){
                    List dataNodes=new ArrayList();
                    node.getParent().getRight().postOrderList(dataNodes);
                node=dataNodes.get(0);


            }

        }

    }
    //前序线索化
    public void threadedPreNodes(DataNode 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()==0){
            threadedPreNodes(node.getLeft());
        }
        if(node.getRightType()==0){
            threadedPreNodes(node.getRight());
        }


    }
    //中序线索化
    public  void threadedNodes(DataNode node){
        if(node==null){
            return;
        }
        //一:先线索化左子树
        threadedNodes(node.getLeft());
        //二:线索化当前节点
        //处理当前节点的前驱节点
        if(node.getLeft()==null){
            //让当前节点的左指针指向前驱节点
            node.setLeft(pre);
            //修改当前节点的左指针的类型
            node.setLeftType(1);
        }
        //处理后继节点
        if(pre!=null && pre.getRight()==null){
            //让前驱节点的右指针指向当前节点
            pre.setRight(node);
            //修改前驱节点的右指针类型
            pre.setRightType(1);
        }
        //更新pre
        pre=node;
        //三:线索化右子树
        threadedNodes(node.getRight());
    }
    //后序线索化
    public void threadedPostNodes(DataNode node){
        if(node==null){
            return;
        }
        //线索化左子树
        threadedPostNodes(node.getLeft());
        //线索化右子树
        threadedPostNodes(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 preOrder(){
        if(this.root!=null){
            this.root.preOrder();
        }else{
            System.out.println("二叉树为空");
        }
    }
    //中序遍历
    public void midOrder(){
        if(this.root!=null){
            this.root.midOrder();
        }else{
            System.out.println("nullpointexception");
        }
    }
    //后序遍历
    public void postOrder(){
        if(this.root!=null){
            this.root.postOrder();
        }else{
            System.out.println("nullpointexception");
        }
    }
    //前序查找
    public DataNode preOrdersearch(int num){
        if(this.root!=null){
            DataNode dataNode = this.root.preOrdersearch(num);
            return  dataNode;
        }else{
            System.out.println("null ");
            return null;
        }
    }
    //中序查找
    public DataNode midOrdersearch(int num){
        if(this.root!=null){
            DataNode dataNode = this.root.midOrdersearch(num);
            return dataNode;
        }else{
            System.out.println("null");
            return null;
        }
    }
    //后序查找
    public DataNode postOrdersearch(int num){
        if(this.root!=null){
            DataNode dataNode = this.root.postOrdersearch(num);
            return  dataNode;
        }else{
            System.out.println("null");
            return null;
        }
    }
    /**删除节点
     * 如果是叶子节点就直接删除该节点
     *如果不是叶子节点 就直接删除该子树
     */
    public void delNode(int num){
        if(root==null){
            System.out.println("树 为空");
            return;
        }
        if(root.getNum()==num){
            root=null;
            return;
        }
        root.delNode(num);

    }

}
//定义节点
class DataNode {
    private int num;
    private String name;
    private DataNode left;
    private DataNode right;
    private int leftType;
    private int rightType;
    private DataNode parent;
    //如果lefttype为0   则表示指向左子树   为1则为指向前驱节点
    //如果righttype为0  则表示指向右子树   为1则表示为指向后继节点
    public DataNode(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public DataNode getParent() {
        return parent;
    }

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

    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 int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getName() {
        return name;
    }

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

    public DataNode getLeft() {
        return left;
    }

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

    public DataNode getRight() {
        return right;
    }

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

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

    //编写前序遍历的方法
    public void preOrder() {
        System.out.println(this);
        //递归向左子树
        if (this.left != null) {
            this.left.preOrder();
        }
        //递归右子树
        if (this.right != null) {
            this.right.preOrder();
        }
    }

    //中序遍历的方法
    public void midOrder() {
        if (this.left != null) {
            this.left.midOrder();
        }
        System.out.println(this);
        if (this.right != null) {
            this.right.midOrder();
        }
    }

    //后序遍历的方法
    public void postOrder() {
        if (this.left != null) {
            this.left.postOrder();
        }
        if (this.right != null) {
            this.right.postOrder();
        }
        System.out.println(this);
    }
    //后序遍历添加进list
    public void postOrderList(List dataNodes){
        if(this.left!=null && this.leftType==0){
            this.left.postOrderList( dataNodes);
        }
        if(this.right!=null && this.rightType==0){
            this.right.postOrderList( dataNodes);
        }
        dataNodes.add(this);
    }

    //前序遍历查找
    public DataNode preOrdersearch(int num) {
        //比较的次数
        int count = 0;
        System.out.println(++count);
        if (this.num == num) {
            return this;
        }
        DataNode resNode = null;
        //判断左子节点是否为空
        if (this.left != null) {
            resNode = this.left.preOrdersearch(num);
        }
        if (resNode != null) {
            return resNode;
        }
        if (this.right != null) {
            resNode = this.right.preOrdersearch(num);
        }
        return resNode;


    }

    //中序遍历查找
    public DataNode midOrdersearch(int num) {
        DataNode resNode = null;
        if (this.left != null) {
            resNode = this.left.midOrdersearch(num);
        }
        if (resNode != null) {
            return resNode;
        }
        //比较的次数
        int count = 0;
        System.out.println(++count);
        if (this.num == num) {
            return this;
        }
        if (this.right != null) {
            resNode = this.right.midOrdersearch(num);
        }
        return resNode;
    }

    //后序遍历查找
    public DataNode postOrdersearch(int num) {
        DataNode resNode = null;
        if (this.left != null) {
            resNode = this.left.postOrdersearch(num);
        }
        if (resNode != null) {
            return resNode;
        }
        if (this.right != null) {
            resNode = this.right.postOrdersearch(num);
        }
        if (resNode != null) {
            return resNode;
        }
        //比较的次数
        int count = 0;
        System.out.println(++count);
        if (this.num == num) {
            return this;
        }
        return null;

    }

    /**
     * 递归删除节点
     * 如果是叶子节点就删除该节点
     * 如果不是叶子节点就删除该子树
     */
    public void delNode(int num) {
        //判断左子节点是否为空,是否权等于我们要删除的
        if (this.left != null && this.left.num == num) {
            this.left = null;
            return;
        }
        //判断右子节点是否为空
        if (this.right != null && this.right.num == num) {
            this.right = null;
            return;
        }
        //向左子树递归
        if (this.left != null) {
            this.left.delNode(num);
        }
        //向右子树递归
        if (this.right != null) {
            this.right.delNode(num);
        }
    }

你可能感兴趣的:(数据结构和算法)