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

二叉树前中后线索化及对应前中后序线索化遍历(图解)

二叉树线索化都是套路,会一种另外两种只是稍微修改一下代码

值得一提的是后序线索化输出,逆序思维将后序线索化看成前序,采用"前序线索化输出"代码更加简洁,也更好理解

线索化基本介绍
在这里插入图片描述
二叉树线索化百度百科介绍:
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 + "]";
	}

}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值