线索二叉树

线索化二叉树

基本概念

线索化二叉树:利用二叉树中的节点的空指针域,分别指向它的前继节点和后继节点

概念:

  • 利用空指针域生成的指向称为线索

  • 根据树结构的前序中序后序遍历的概念,有前序中序后序线索二叉树

  • 一个节点的前一个节点称为前继节点

  • 一个节点的后一个节点称为后继节点

说明:二叉树进行线索化后,其左指针域可能是左子树或者前继节点,右指针域可能是右子树或者后继节点

此章节举例二叉树为

前序结果:1,3,8,10,6,14

中序结果:8,3,10,1,14,6

后序结果:8,10,3,14,6,1

二叉树构造

//构造二叉树
TreeNode node1 = new TreeNode(1);
TreeNode node3 = new TreeNode(3);
TreeNode node6 = new TreeNode(6);
TreeNode node8 = new TreeNode(8);
TreeNode node10 = new TreeNode(10);
TreeNode node14 = new TreeNode(14);
node1.setLeft(node3);
node3.setLeft(node8);
node3.setRight(node10);
node1.setRight(node6);
node6.setLeft(node14);
// 设置父节点,用于后续遍历线索二叉树
node3.setParent(node1);
node8.setParent(node3);
node10.setParent(node3);
node14.setParent(node6);
node6.setParent(node1);
//节点属性
class TreeNode
{
private int value;// 权值
private TreeNode left;// 左子节点
private TreeNode right;// 右子节点
private int leftType;// 左边子节点类型 为0则是子树,为1则是前继或后继节点
private int rightType;// 右边子节点类型

private TreeNode parent;// 父节点,用于后序遍历线索二叉树

 

前序中序后序线索化二叉树

前序线索化二叉树:

  • 思路:

    1. 根据前序遍历的顺序(根左右),先处理根节点,再递归处理左节点和右节点。从根节点开始

    2. 递归处理左节点,直到叶子节点(要交换pre节点)

    3. 递归处理右节点,直到结束

    • !!!注意:在进行左右递归是,要判断左右的节点类型(因为是先设置的左右节点会死循环)

  • 代码

    //线索化二叉树(前序)
    public void changeTreePre(TreeNode node)
    {
    if (node == null)
    {
    return;
    }
    // 设置前驱节点(因为实在递归过程中的[递]过程进行前继节点赋值,所以时node指向pre)
    if (node.getLeft() == null)
    {
    node.setLeft(pre);
    node.setLeftType(1);
    }
    // 设置后驱节点(因为是在递归过程中的[归]过程进行后继节点赋值,所以是用pre指向node)
    if (pre != null && pre.getRight() == null)
    {
    pre.setRight(node);
    pre.setRightType(1);
    }
    // pre值改变
    pre = node;
    // 左子树递归
    if (node.getLeftType() != 1)
    {
    changeTreePre(node.getLeft());
    }
    // 右子树递归
    if (node.getRightType() != 1)
    {
    changeTreePre(node.getRight());
    }
    }

中序线索化二叉树:

  • 思路:

    1. 根据中序遍历的顺序(左根右),先递归处理左节点,再处理根节点,再递归处理右节点。

    2. 左子树递归找到中序起点

    3. 处理根节点的前继后继节点

    4. 递归处理右节点,直到结束

  • 代码

    // 线索化二叉树(中序)
    public void changeTreeMid(TreeNode node)
    {
    // 找到中序遍历的起始节点
    if (node == null)
    {
    return;
    }
    // 左子树递归
    changeTreeMid(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;
    // 右子树递归
    changeTreeMid(node.getRight());
    }

后序线索化二叉树:

  • 思路:

    1. 根据后序遍历的顺序(左右根),先递归处理左节点,再递归处理右节点,再处理根节点

    2. 左子树递归找到后序起点

    3. 右子树递归

    4. 设置根节点的前后继节点,直到结束

  • 代码

    //线索化二叉树(后序)
    public void changeTreeNext(TreeNode node)
    {
    if (node == null)
    {
    return;
    }

    // 向左递归
    changeTreeNext(node.getLeft());
    // 向右递归
    changeTreeNext(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值修改
    pre = node;
    }

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

前序线索二叉树遍历:

  • 思路:

    1. 根据前序特点(根左右)

    2. 输出根节点(只要左节点类型是子树)

    3. 根据后继节点输出,则前序线索二叉树遍历完毕

  • 代码

    // 前序线索二叉树遍历
    public void iteratorPre()
    {
    TreeNode node = root;
    // while(node!=null &&node.getLeftType()==0) {
    // System.out.println(node.getValue());
    // while(node.getLeftType()==0) {
    // node=node.getLeft();
    // System.out.println(node.getValue());
    // }
    // while(node.getRightType()==1) {
    // node=node.getRight();
    // System.out.println(node.getValue());
    // }
    // }

    //以上为自己写的前序
    //一下是参考别人的前序,相对来说更简洁



    while (node != null)
    {
    System.out.print(node.getValue() + " ");
    // 如果存在左子节点就往左走,否则往右走,此时右指针一定是前序遍历的下一个节点
    if (node.getLeftType() == 0)
    {
    node = node.getLeft();
    } else
    {
    node = node.getRight();
    }
    }
    }

中序线索二叉树遍历:

  • 思路:

    1. 根据中序特点(左根右)

    2. 左子树递归(找到起点)

    3. 由起点开始向后遍历(通过后继节点)

    4. 当不再是后继节点时,将node置为node的右节点(因为左根右,到了根节点时,要遍历右节点)

  • 代码

    // 中序线索二叉树遍历
    public void iteratorMid()
    {
    TreeNode node = root;
    while (node != null)
    {
    // 找到中序起始节点
    while (node.getLeftType() == 0)
    {// 左指针为左子节点
    node = node.getLeft();
    }
    System.out.println(node.getValue());
    while (node.getRightType() == 1)
    {// 为后继节点
    node = node.getRight();
    System.out.println(node.getValue());
    }
    node = node.getRight();

    }
    }

后序线索二叉树遍历:

  • 说明:后序线索二叉树遍历时,需要用的父节点属性,在前面已经设置完毕

  • 思路:

    1. 根据后序遍历顺序(左右根)

    2. 左子树递归找到后序起点

    3. 判断节点类型

      • 节点的右节点是后继节点,输出节点,并替换pre,node=right

      • 节点的不是后继节点的情况

        1. 节点的右节点是上一个节点,打印节点(此时左右根均已输出),则要找父节点的的右节点,则替换pre并且node=parent

        2. 节点的右节点不是上一个节点,node=right,递归处理右子树

  • 代码

    // 后序线索二叉树遍历
    public void iteratorNext()
    {
    TreeNode node = root;
    // 找后序起始节点
    while (node.getLeftType() == 0)
    {
    node = node.getLeft();
    }
    while (node != null)
    {
    // 判断起始节点的右节点是否是后继节点
    if (node.getRightType() == 1)
    {
    System.out.println(node.getValue());
    pre = node;
    node = node.getRight();
    } else
    {
    // 判断是否是处理节点的父节点
    if (node.getRight() == pre)
    {
    System.out.println(node.getValue());

    // 结束条件(输出根节点)
    if (node == root)
    {
    return;
    }

    pre = node;
    node = node.getParent();
    } else{
    node = node.getRight();
    while (node != null && node.getLeftType() == 0)
    {
    node = node.getLeft();
    }
    }
    }
    }
    }

     

  •  

posted @ 2021-02-25 15:26  leo_host  阅读(166)  评论(0)    收藏  举报