二叉树前中后线索化及对应前中后序线索化遍历(图解)
二叉树线索化都是套路,会一种另外两种只是稍微修改一下代码
值得一提的是后序线索化输出,逆序思维将后序线索化看成前序,采用"前序线索化输出"代码更加简洁,也更好理解
线索化基本介绍
二叉树线索化百度百科介绍:
https://baike.baidu.com/item/%E7%BA%BF%E7%B4%A2%E4%BA%8C%E5%8F%89%E6%A0%91/10810037?fr=aladdin
以下面二叉树为例
前序化流程图解
创建节点对象 (使用数组更方便)
class TreeNode1 {
private int no;
private TreeNode1 left;
private TreeNode1 right;
/*
* 说明: 1.如果 letfType 或 rightType 为 0 表示 左子树或右子树 2.如果 letfType 或 rightType 为 1 表示
* 前驱或后驱节点
*/
private int leftType;
private int rightType;
public TreeNode1(int no) {
this.no = no;
}
//getter/setter ...
@Override
public String toString() {
return "TreeNode1 [no=" + no + "]";
}
}
创建一个类实现线索化
class TreeManger1 {
private TreeNode1 root;
public void setRoot(TreeNode1 root) {
this.root = root;
}
...线索化
}
## 中序最简单也最容易理解 所以先看一下中序线索化
// 为了实现 线索化,需要创建一个变量,指定向前节点的前驱节点
// 在递归进行索化时,infixPre 总是保留前一个节点
TreeNode1 infixPre = null;
public void infixThreadTreeNode() {
this.infixThreadTreeNode(root);
}
// 中序线索化
public void infixThreadTreeNode(TreeNode1 node) {
// 如果 node == null 则不能索化
if (node == null) {
return;
}
// 1.线索化左子树
infixThreadTreeNode(node.getLeft());
// 2.线索化当前节点
if (node.getLeft() == null) {
// 让当前节点的左指针指向前驱节点
node.setLeft(infixPre);
// 修改当前节点的左指针的类型,指向前驱节点
node.setLeftType(1);
}
// 处理后继节点
if (infixPre != null && infixPre.getRight() == null) {
// 让前驱节点的有指针指向当前节点
infixPre.setRight(node);
// 修改前驱节点的右指针类型
infixPre.setRightType(1);
}
// !!!!!没处理一个节点后让当前节点指向下一个节点的前驱节点
infixPre = node;
// 3.线索化右子树
infixThreadTreeNode(node.getRight());
}
中序线索化遍历
// 中序线索化输出
public void infixThreadTreeNodeOrde() {
// 定义一个节点存储当前遍历的节点 从 root 开始
TreeNode1 node = root;
while (node != null) {
// 循环找到 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();
}
}
前序线索化
TreeNode1 prePre = null;
// 前序线索化
public void preThread(TreeNode1 node) {
if (node == null) {
return;
}
// 线索化当前节点
if (node.getLeft() == null) {
node.setLeft(prePre);
node.setLeftType(1);
}
if (prePre != null && prePre.getRight() == null) {
prePre.setRight(node);
prePre.setRightType(1);
}
prePre = node;
// 线索化左子树
if (node.getLeftType() != 1) {
preThread(node.getLeft());
}
// 线索化右子树
if (node.getRightType() != 1) {
preThread(node.getRight());
}
}
前序线索化输出
// 前序索化输出
public void preThreadOrder() {
TreeNode1 node = root;
while (node != null) {
while (node.getLeftType() != 1) {
System.out.println(node);
node = node.getLeft();
}
System.out.println(node);
node = node.getRight();
}
}
后序线索化
TreeNode1 postPre = null;
// 后序序线索化
public void postThread(TreeNode1 node) {
if (node == null) {
return;
}
// 线索化左子树
postThread(node.getLeft());
// 线索化右子树
postThread(node.getRight());
// 线索化当前节点
if (node.getLeft() == null) {
node.setLeft(postPre);
node.setLeftType(1);
}
if (postPre != null && postPre.getRight() == null) {
postPre.setRight(node);
postPre.setRightType(1);
}
postPre = node;
}
后序线索化输出
/*
* 后线索化输出
*
* 逆序前线索化,将其压入栈中,最后依次弹出即可
*
*/
public void postThreadOrde() {
Stack<TreeNode1> stack = new Stack<TreeNode1>();
TreeNode1 node = root;
while (node != null) {
while (node.getRightType() != 1) {
stack.push(node);
node = node.getRight();
}
stack.push(node);
node = node.getLeft();
}
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
}
一张图对比一下 其实都是套路
全部代码
package com.kc.c09_tree._02threadbinarytree;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class T {
public static void main(String[] args) {
TreeNode1 n11 = new TreeNode1(11);
TreeNode1 n21 = new TreeNode1(21);
TreeNode1 n31 = new TreeNode1(31);
TreeNode1 n14 = new TreeNode1(14);
TreeNode1 n15 = new TreeNode1(15);
TreeNode1 n61 = new TreeNode1(61);
TreeNode1 n71 = new TreeNode1(71);
TreeNode1 n81 = new TreeNode1(81);
TreeNode1 n91 = new TreeNode1(91);
n11.setLeft(n21);
n11.setRight(n31);
n21.setLeft(n14);
n21.setRight(n15);
n31.setLeft(n61);
n31.setRight(n71);
n14.setLeft(n81);
n14.setRight(n91);
TreeManger1 tm = new TreeManger1();
tm.setRoot(n11);
// tm.preThread(n11);
// tm.infixThreadTreeNode(n11);
tm.postThread(n11);
//
// 检验
TreeNode1 left11 = n11.getLeft();
TreeNode1 right11 = n11.getRight();
System.out.println("no11 : left = " + left11 + ",right = " + right11);
TreeNode1 left21 = n21.getLeft();
TreeNode1 right21 = n21.getRight();
System.out.println("no21 : left = " + left21 + ",right = " + right21);
TreeNode1 left31 = n31.getLeft();
TreeNode1 right31 = n31.getRight();
System.out.println("no31 : left = " + left31 + ",right = " + right31);
TreeNode1 left14 = n14.getLeft();
TreeNode1 right14 = n14.getRight();
System.out.println("no14 : left = " + left14 + ",right = " + right14);
TreeNode1 left81 = n81.getLeft();
TreeNode1 right81 = n81.getRight();
System.out.println("no81 : left = " + left81 + ",right = " + right81);
TreeNode1 left91 = n91.getLeft();
TreeNode1 right91 = n91.getRight();
System.out.println("no91 : left = " + left91 + ",right = " + right91);
TreeNode1 left15 = n15.getLeft();
TreeNode1 right15 = n15.getRight();
System.out.println("no15 : left = " + left15 + ",right = " + right15);
TreeNode1 left61 = n61.getLeft();
TreeNode1 right61 = n61.getRight();
System.out.println("no61 : left = " + left61 + ",right = " + right61);
TreeNode1 left71 = n71.getLeft();
TreeNode1 right71 = n71.getRight();
System.out.println("no71 : left = " + left71 + ",right = " + right71);
// tm.preThreadOrder();
// tm.infixThreadTreeNodeOrde();
tm.postThreadOrde();
}
}
class TreeManger1 {
private TreeNode1 root;
public void setRoot(TreeNode1 root) {
this.root = root;
}
/********* 线索化二叉树 *********/
/******************************************/
TreeNode1 prePre = null;
// 前序线索化
public void preThread(TreeNode1 node) {
if (node == null) {
return;
}
// 线索化当前节点
if (node.getLeft() == null) {
node.setLeft(prePre);
node.setLeftType(1);
}
if (prePre != null && prePre.getRight() == null) {
prePre.setRight(node);
prePre.setRightType(1);
}
prePre = node;
// 线索化左子树
if (node.getLeftType() != 1) {
preThread(node.getLeft());
}
// 线索化右子树
if (node.getRightType() != 1) {
preThread(node.getRight());
}
}
// 前序索化输出
public void preThreadOrder() {
TreeNode1 node = root;
while (node != null) {
while (node.getLeftType() != 1) {
System.out.println(node);
node = node.getLeft();
}
System.out.println(node);
node = node.getRight();
}
}
/******************************************/
TreeNode1 postPre = null;
// 后序序线索化
public void postThread(TreeNode1 node) {
if (node == null) {
return;
}
// 线索化左子树
postThread(node.getLeft());
// 线索化右子树
postThread(node.getRight());
// 线索化当前节点
if (node.getLeft() == null) {
node.setLeft(postPre);
node.setLeftType(1);
}
if (postPre != null && postPre.getRight() == null) {
postPre.setRight(node);
postPre.setRightType(1);
}
postPre = node;
}
/*
* 后线索化输出
*
* 逆序前线索化,将其压入栈中,最后依次弹出即可
*
*/
public void postThreadOrde() {
Stack<TreeNode1> stack = new Stack<TreeNode1>();
TreeNode1 node = root;
while (node != null) {
while (node.getRightType() != 1) {
stack.push(node);
node = node.getRight();
}
stack.push(node);
node = node.getLeft();
}
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
}
/*************************************/
// 为了实现 线索化,需要创建一个变量,指定向前节点的前驱节点
// 在递归进行索化时,infixPre 总是保留前一个节点
TreeNode1 infixPre = null;
public void infixThreadTreeNode() {
this.infixThreadTreeNode(root);
}
// 中序线索化
public void infixThreadTreeNode(TreeNode1 node) {
// 如果 node == null 则不能索化
if (node == null) {
return;
}
// 1.线索化左子树
infixThreadTreeNode(node.getLeft());
// 2.线索化当前节点
if (node.getLeft() == null) {
// 让当前节点的左指针指向前驱节点
node.setLeft(infixPre);
// 修改当前节点的左指针的类型,指向前驱节点
node.setLeftType(1);
}
// 处理后继节点
if (infixPre != null && infixPre.getRight() == null) {
// 让前驱节点的有指针指向当前节点
infixPre.setRight(node);
// 修改前驱节点的右指针类型
infixPre.setRightType(1);
}
// !!!!!没处理一个节点后让当前节点指向下一个节点的前驱节点
infixPre = node;
// 3.线索化右子树
infixThreadTreeNode(node.getRight());
}
// 中序线索化输出
public void infixThreadTreeNodeOrde() {
// 定义一个节点存储当前遍历的节点 从 root 开始
TreeNode1 node = root;
while (node != null) {
// 循环找到 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();
}
}
}
class TreeNode1 {
private int no;
private TreeNode1 left;
private TreeNode1 right;
private int leftType;
private int rightType;
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 TreeNode1(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public TreeNode1 getLeft() {
return left;
}
public void setLeft(TreeNode1 left) {
this.left = left;
}
public TreeNode1 getRight() {
return right;
}
public void setRight(TreeNode1 right) {
this.right = right;
}
@Override
public String toString() {
return "TreeNode1 [no=" + no + "]";
}
}