Java数据结构和算法之前中后序线索化二叉树、前中遍历二叉树

线索二叉树基本介绍:
  1. n个结点的二叉链表中含有n+1 【公式 2n-(n-1)=n+1】 个空指针域。利用二叉链表中的空指针域,存放指向该结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")。

  2. 这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。

  3. 一个结点的前一个结点,称为前驱结点。

  4. 一个结点的后一个结点,称为后继结点。

线索二叉树应用案例:

应用案例说明:将下面的二叉树,进行中序线索二叉树。中序遍历的数列为 {8, 3, 10, 1, 14, 6}
在这里插入图片描述

代码如下:
package com.atguigu.treedemo.threadtree;


public class ThreadTreeDemo {
	public static void main(String[] args) {
		TreeNode node1 = new TreeNode(1);
		TreeNode node2 = new TreeNode(3);
		TreeNode node3 = new TreeNode(6);
		TreeNode node4 = new TreeNode(8);
		TreeNode node5 = new TreeNode(10);
		TreeNode node6 = new TreeNode(14);
		
		node1.setLeft(node2);
		node1.setRight(node3);
		node2.setLeft(node4);
		node2.setRight(node5);
		node3.setLeft(node6);
		
		BinaryTree binaryTree = new BinaryTree(node1);
//		binaryTree.threadTree(node1);
//		binaryTree.preThreadTree(node1);
		binaryTree.posThreadTree(node1);
		
		System.out.println(node4.getLeft());
		System.out.println(node4.getRight());
		System.out.println(node3.getLeft());
		System.out.println(node3.getRight());
		
//		System.out.println("中序遍历线索化二叉树:");
//		binaryTree.listThreadTree();
		
//		System.out.println("前序遍历线索化二叉树:");
//		binaryTree.preListThreadTree();
		
	}
}


//定义一个二叉树的实现类
class BinaryTree {
	private TreeNode root; // 代表树的根节点
	private TreeNode pre = null; // 指向前驱节点

	// 构造器
	public BinaryTree(TreeNode root) {
		this.root = root;
	}
	
	// 前序遍历线索化二叉树
	public void preListThreadTree() {
		TreeNode 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 listThreadTree() {
		// 定义一个变量存储当前遍历的节点,从root开始
		TreeNode node = root;
		while(node != null) {
			// 循环的找到leftType == 1的节点,第一个找到的就是8节点
			// 后面循环着遍历而变化,因为当rightType==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();
		}
	}
	
	
	// 前序线索化二叉树
	public void preThreadTree(TreeNode node) {
		// 如果node == null ,此时该节点无法线索化
		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) {
			preThreadTree(node.getLeft());
		}
		if(node.getRightType() == 0) {
			preThreadTree(node.getRight());
		}	
	}
	
	// 中序线索化二叉树
	public void threadTree(TreeNode node) {
		// 如果node == null 不能线索化
		if(node == null) {
			return ;
		}
		
		// (一) 先线索化左子树
		threadTree(node.getLeft());
		// (二) 线索化当前节点
		// 处理当前节点的前驱节点
		// 以8节点来理解
		// 8节点的 .left = null , 8节点的 .leftType = 1
		if(node.getLeft() == null) {
			// 让当前节点的左指针指向前驱节点
			node.setLeft(pre);
			// 修改当前节点的左指针类型,指向前驱节点
			node.setLeftType(1);
		}
		// 处理后继节点
		if(pre != null && pre.getRight() == null) {
			// 让前驱节点的右指针指向当前节点
			pre.setRight(node);
			// 修改前驱节点的右指针类型
			pre.setRightType(1);
		}
		// !!!每处理一个节点后,让当前节点是下一个节点的前驱节点
		pre = node;
		
		// (三) 再线索化右子树
		threadTree(node.getRight());
	}

	// 后序线索化二叉树
	public void posThreadTree(TreeNode node) {
		if(node == null) {
			return ;
		}
		
		posThreadTree(node.getLeft());
		posThreadTree(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;
	}
}

//定义一个节点类
class TreeNode {
	private int data; // 用来存放节点数据
	private TreeNode right; // 指向该节点的右子树
	private TreeNode left; // 指向该节点的左子树
	/*
	 * leftType 为0代表的是指向的为左子树,leftType为1代表的是指向前前驱节点或者是后继节点 
	 */
	private int leftType; // 用来标明左子树的指向类型
	private int rightType; // 用来标明右子树的指向类型

	// 构造器
	public TreeNode(int data) {
		this.data = data;
	}

	/*
	 * 定义属性的get和set方法
	 */
	public TreeNode getRight() {
		return right;
	}

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

	public TreeNode getLeft() {
		return left;
	}

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

	public int getData() {
		return data;
	}
	
	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;
	}

	@Override
	public String toString() {
		return "TreeNode [data=" + data + "]";
	}
}
总结:

对于二叉树的后续遍历为什么没写?因为后续遍历线索二叉树时还需要一个指针指向parent,逻辑相对复杂。线索二叉树的优势无非就是提高了遍历的效率,所以能掌握前中遍历就可以了。当前你要追求更高的境界更好。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值