IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构与算法(十三)——二叉树 -> 正文阅读

[数据结构与算法]数据结构与算法(十三)——二叉树

二叉树的遍历

  1. 前(根)序遍历:先输出父节点,再遍历左子树和右子树
  2. 中(根)序遍历:先输出左子树,再输出父节点,在输出右子树
  3. 后(根)序遍历:先输出左子树,在输出右子树,最后输出父结点
  4. 三种遍历方式的区别在于根节点的输出时机

代码实现

/***
 * 二叉树
 * @author laowa
 *
 */
class BinaryTree{
	/**
	 * 根节点
	 */
	Node root;
	public BinaryTree(Node root) {
		this.root = root;
	}
	
	
	/**
	 * 先序遍历
	 */
	public void preOrder() {
		if(this.root==null) {
			System.out.println("二叉树为空");
		}
		this.root.preOrder();
	}
	
	/**
	 * 中序遍历
	 */
	public void infixOrder() {
		if(this.root==null) {
			System.out.println("二叉树为空");
		}
		this.root.infixOrder();
	}
	
	/**
	 * 后序遍历
	 */
	public void postOrder() {
		if(this.root==null) {
			System.out.println("二叉树为空");
		}
		this.root.postOrder();
	}
}


/**
 * 树的节点
 * @author laowa
 *
 */
class Node{
	int no;
	String name;
	/**
	 * 左子节点
	 */
	Node left;
	/**
	 * 右子节点
	 */
	Node right;
	
	public Node(int no,String name) {
		this.no = no;
		this.name = name;
	}
	
	@Override
	public String toString() {
		return "[no="+no+"\tname="+name+"]";
	}
	
	/**
	 * 先序遍历
	 */
	public void preOrder() {
		//1.打印当前节点
		System.out.println(this);
		//2.如果左子树不为空,则向左递归遍历
		if(this.left!=null) {
			this.left.preOrder();
		}
		//3.如果有子树不为空,则向右递归遍历
		if(this.right!=null) {
			this.right.preOrder();
		}
	}
	
	/**
	 * 中序遍历
	 */
	public void infixOrder() {
		//1.如果左子树不为空,则向左递归遍历
		if(this.left!=null) {
			this.left.infixOrder();
		}
		//2.打印当前节点
		System.out.println(this);
		//3.如果右子树不为空,则向右递归遍历
		if(this.right!=null) {
			this.right.infixOrder();
		}
	}
	
	/**
	 * 后序遍历
	 */
	public void postOrder() {
		//1.如果左子树不为空,则向左递归遍历
		if(this.left!=null) {
			this.left.postOrder();
		}
		//2.如果右子树不为空,则向右递归遍历
		if(this.right!=null) {
			this.right.postOrder();
		}
		//3.打印当前节点
		System.out.println(this);
	}
	
	
}

二叉树的查找

二叉树的查找和遍历一样,也分前、中、后序查找;根据比对树中节点的顺序来区分

代码实现

/***
 * 二叉树
 * 
 * @author laowa
 *
 */
class BinaryTree {
	/**
	 * 根节点
	 */
	Node root;

	public BinaryTree(Node root) {
		this.root = root;
	}

	/**
	 * 先序遍历
	 */
	public void preOrder() {
		if (this.root == null) {
			System.out.println("二叉树为空");
		}
		this.root.preOrder();
	}

	/**
	 * 中序遍历
	 */
	public void infixOrder() {
		if (this.root == null) {
			System.out.println("二叉树为空");
		}
		this.root.infixOrder();
	}

	/**
	 * 后序遍历
	 */
	public void postOrder() {
		if (this.root == null) {
			System.out.println("二叉树为空");
		}
		this.root.postOrder();
	}
	
	/**
	 * 前序查找
	 * @param no 目标节点编号
	 * @return 目标节点
	 */
	public Node preSearch(int no) {
		Node helper = this.root.preSearch(no);
		if(helper==null) {
			throw new RuntimeException("没有找到目标节点");
		}
		return helper;
	}
	
	/**
	 * 中序查找
	 * @param no 目标节点编号
	 * @return 目标节点
	 */
	public Node infixSearch(int no) {
		Node helper = this.root.infixSearch(no);
		if(helper==null) {
			throw new RuntimeException("没有找到目标节点");
		}
		return helper;
	}
	
	/**
	 * 后序查找
	 * @param no 目标节点编号
	 * @return 目标节点
	 */
	public Node postSearch(int no) {
		Node helper = this.root.postSearch(no);
		if(helper==null) {
			throw new RuntimeException("没有找到目标节点");
		}
		return helper;
	}
	
}

/**
 * 树的节点
 * 
 * @author laowa
 *
 */
class Node {
	int no;
	String name;
	/**
	 * 左子节点
	 */
	Node left;
	/**
	 * 右子节点
	 */
	Node right;

	public Node(int no, String name) {
		this.no = no;
		this.name = name;
	}

	@Override
	public String toString() {
		return "[no=" + no + "\tname=" + name + "]";
	}

	/**
	 * 先序遍历
	 */
	public void preOrder() {
		// 1.打印当前节点
		System.out.println(this);
		// 2.如果左子树不为空,则向左递归遍历
		if (this.left != null) {
			this.left.preOrder();
		}
		// 3.如果有子树不为空,则向右递归遍历
		if (this.right != null) {
			this.right.preOrder();
		}
	}

	/**
	 * 中序遍历
	 */
	public void infixOrder() {
		// 1.如果左子树不为空,则向左递归遍历
		if (this.left != null) {
			this.left.infixOrder();
		}
		// 2.打印当前节点
		System.out.println(this);
		// 3.如果右子树不为空,则向右递归遍历
		if (this.right != null) {
			this.right.infixOrder();
		}
	}

	/**
	 * 后序遍历
	 */
	public void postOrder() {
		// 1.如果左子树不为空,则向左递归遍历
		if (this.left != null) {
			this.left.postOrder();
		}
		// 2.如果右子树不为空,则向右递归遍历
		if (this.right != null) {
			this.right.postOrder();
		}
		// 3.打印当前节点
		System.out.println(this);
	}

	/**
	 * 前序查找
	 * 
	 * @param no
	 *            目标节点的编号
	 * @return 目标节点
	 */
	public Node preSearch(int no) {
		// 辅助节点,存储找到的目标节点
		Node helper = null;
		// 1.判断当前节点是否是目标节点
		if (this.no == no) {
			helper = this;
		}
		// 2.如果左子树不为空,且目标节点还没有找到,则向左子树递归查找
		if (this.left != null && helper == null) {
			helper = this.left.preSearch(no);
		}
		// 3.如果右子树不为空,且目标节点还没有找到,则向右子树递归查找
		if (right != null && helper == null) {
			helper = this.right.preSearch(no);
		}
		// 返回最终结果
		return helper;
	}

	/**
	 * 中序查找
	 * 
	 * @param no
	 *            目标节点的编号
	 * @return 目标节点
	 */
	public Node infixSearch(int no) {
		// 辅助节点,存储找到的目标节点
		Node helper = null;
		// 1.如果左子节点不为空,则向左递归查找
		if (this.left != null) {
			helper = this.left.infixSearch(no);
		}
		// 2.如果左子树没找到目标节点,判断当前是否是目标节点
		if (helper == null && this.no == no) {
			helper = this;
		}
		// 3.如果左子树和当前当前节点都没有找到,则向右递归查找
		if (helper == null && this.right != null) {
			helper = this.right.infixSearch(no);
		}
		return helper;
	}

	/**
	 * 后序查找
	 * 
	 * @param no
	 *            目标节点的编号
	 * @return 目标节点
	 */
	public Node postSearch(int no) {
		// 辅助节点,存储找到的目标节点
		Node helper = null;
		// 1.如果左子节点不为空,则向左递归查找
		if (this.left != null) {
			helper = this.left.postSearch(no);
		}
		// 3.如果左子树和当前当前节点都没有找到,则向右递归查找
		if (helper == null && this.right != null) {
			helper = this.right.postSearch(no);
		}
		// 2.如果左子树没找到目标节点,判断当前是否是目标节点
		if (helper == null && this.no == no) {
			helper = this;
		}
		return helper;
	}

}

二叉树的简单删除

  1. 如果删除的是叶子节点,将该叶子节点的父节点的指针置空
  2. 如果删除的是非叶子节点,删除该节点为根节点的整颗子树

代码实现

/***
 * 二叉树
 * 
 * @author laowa
 *
 */
class BinaryTree {
	/**
	 * 根节点
	 */
	Node root;

	public BinaryTree(Node root) {
		this.root = root;
	}

	/**
	 * 先序遍历
	 */
	public void preOrder() {
		if (this.root == null) {
			System.out.println("二叉树为空");
			return;
		}
		this.root.preOrder();
	}

	/**
	 * 中序遍历
	 */
	public void infixOrder() {
		if (this.root == null) {
			System.out.println("二叉树为空");
			return;
		}
		this.root.infixOrder();
	}

	/**
	 * 后序遍历
	 */
	public void postOrder() {
		if (this.root == null) {
			System.out.println("二叉树为空");
			return;
		}
		this.root.postOrder();
	}
	
	/**
	 * 前序查找
	 * @param no 目标节点编号
	 * @return 目标节点
	 */
	public Node preSearch(int no) {
		Node helper = this.root.preSearch(no);
		if(helper==null) {
			throw new RuntimeException("没有找到目标节点");
		}
		return helper;
	}
	
	/**
	 * 中序查找
	 * @param no 目标节点编号
	 * @return 目标节点
	 */
	public Node infixSearch(int no) {
		Node helper = this.root.infixSearch(no);
		if(helper==null) {
			throw new RuntimeException("没有找到目标节点");
		}
		return helper;
	}
	
	/**
	 * 后序查找
	 * @param no 目标节点编号
	 * @return 目标节点
	 */
	public Node postSearch(int no) {
		Node helper = this.root.postSearch(no);
		if(helper==null) {
			throw new RuntimeException("没有找到目标节点");
		}
		return helper;
	}
	
	/**
	 * 删除节点
	 * @param no 待删除的节点编号
	 */
	public void delete(int no) {
		if(this.root==null) {
			System.out.println("树为空");
			return;
		}
		//如果待删的是根节点,则根节点置空
		if(root.no==no) {
			root = null;
			return;
		}
		this.root.delete(no);
	}
	
}

/**
 * 树的节点
 * 
 * @author laowa
 *
 */
class Node {
	int no;
	String name;
	/**
	 * 左子节点
	 */
	Node left;
	/**
	 * 右子节点
	 */
	Node right;

	public Node(int no, String name) {
		this.no = no;
		this.name = name;
	}

	@Override
	public String toString() {
		return "[no=" + no + "\tname=" + name + "]";
	}

	/**
	 * 先序遍历
	 */
	public void preOrder() {
		// 1.打印当前节点
		System.out.println(this);
		// 2.如果左子树不为空,则向左递归遍历
		if (this.left != null) {
			this.left.preOrder();
		}
		// 3.如果有子树不为空,则向右递归遍历
		if (this.right != null) {
			this.right.preOrder();
		}
	}

	/**
	 * 中序遍历
	 */
	public void infixOrder() {
		// 1.如果左子树不为空,则向左递归遍历
		if (this.left != null) {
			this.left.infixOrder();
		}
		// 2.打印当前节点
		System.out.println(this);
		// 3.如果右子树不为空,则向右递归遍历
		if (this.right != null) {
			this.right.infixOrder();
		}
	}

	/**
	 * 后序遍历
	 */
	public void postOrder() {
		// 1.如果左子树不为空,则向左递归遍历
		if (this.left != null) {
			this.left.postOrder();
		}
		// 2.如果右子树不为空,则向右递归遍历
		if (this.right != null) {
			this.right.postOrder();
		}
		// 3.打印当前节点
		System.out.println(this);
	}

	/**
	 * 前序查找
	 * 
	 * @param no
	 *            目标节点的编号
	 * @return 目标节点
	 */
	public Node preSearch(int no) {
		// 辅助节点,存储找到的目标节点
		Node helper = null;
		// 1.判断当前节点是否是目标节点
		if (this.no == no) {
			helper = this;
		}
		// 2.如果左子树不为空,且目标节点还没有找到,则向左子树递归查找
		if (this.left != null && helper == null) {
			helper = this.left.preSearch(no);
		}
		// 3.如果右子树不为空,且目标节点还没有找到,则向右子树递归查找
		if (right != null && helper == null) {
			helper = this.right.preSearch(no);
		}
		// 返回最终结果
		return helper;
	}

	/**
	 * 中序查找
	 * 
	 * @param no
	 *            目标节点的编号
	 * @return 目标节点
	 */
	public Node infixSearch(int no) {
		// 辅助节点,存储找到的目标节点
		Node helper = null;
		// 1.如果左子节点不为空,则向左递归查找
		if (this.left != null) {
			helper = this.left.infixSearch(no);
		}
		// 2.如果左子树没找到目标节点,判断当前是否是目标节点
		if (helper == null && this.no == no) {
			helper = this;
		}
		// 3.如果左子树和当前当前节点都没有找到,则向右递归查找
		if (helper == null && this.right != null) {
			helper = this.right.infixSearch(no);
		}
		return helper;
	}

	/**
	 * 后序查找
	 * 
	 * @param no
	 *            目标节点的编号
	 * @return 目标节点
	 */
	public Node postSearch(int no) {
		// 辅助节点,存储找到的目标节点
		Node helper = null;
		// 1.如果左子节点不为空,则向左递归查找
		if (this.left != null) {
			helper = this.left.postSearch(no);
		}
		// 3.如果左子树和当前当前节点都没有找到,则向右递归查找
		if (helper == null && this.right != null) {
			helper = this.right.postSearch(no);
		}
		// 2.如果左子树没找到目标节点,判断当前是否是目标节点
		if (helper == null && this.no == no) {
			helper = this;
		}
		return helper;
	}
	
	/**
	 * 删除节点
	 * @param no 待删除节点编号
	 */
	public void delete(int no) {
		//1.判断左节点是否是目标节点
		if(this.left!=null&&this.left.no==no) {
			this.left=null;
			return;
		}
		//2. 如果左子树不为空,则向左递归删除
		if(this.left!=null) {
			this.left.delete(no);
		}
		//3. 判断右节点是否是目标节点
		if(this.right!=null&&this.right.no==no) {
			this.right=null;
			return;
		}
		//4.如果有子树不为空则向右递归删除
		if(this.right!=null) {
			this.right.delete(no);
		}
	}

}

顺序存储二叉树

从数据存储来看,数组存储方式和树存储方式可以相互转换;顺序存储的数组在遍历的时候使用树的遍历方式
在这里插入图片描述

特点

  1. 顺序二叉树通常只考虑完全二叉树
  2. 第n个元素的左子节点为2n+1
  3. 第n个元素的右子节点为2n+2
  4. 第n个元素的父节点为(n-1)/2

代码实现

/***
 * 顺序存储二叉树
 * @author laowa
 *
 */
class ArrayBinaryTree{
	/**
	 * 存储数据节点的数组
	 */
	private int []arr;
	
	public ArrayBinaryTree(int[] arr) {
		this.arr = arr;
	}
	
	/**
	 * 先序遍历
	 */
	public void preOrder() {
		preOrder(0);
	}
	
	/**
	 * 中序遍历
	 */
	public void infixOrder() {
		infixOrder(0);
	}
	
	/**
	 * 后序遍历
	 */
	public void postOrder() {
		postOrder(0);
	}
	
	/**
	 * 先序遍历
	 * @param index 根节点的索引
	 */
	private void preOrder(int index) {
		//判空
		if(arr==null||arr.length==0) {
			System.out.println("空树");
			return;
		}
		//输出当前元素
		System.out.println(arr[index]);
		//向左递归遍历,2*index+1即左子节点的索引
		if((2*index+1)< arr.length) {
			preOrder(2*index+1);
		}
		//向右递归遍历,2*index+2即右子节点的索引
		if((2*index+2)<arr.length) {
			preOrder(2*index+2);
		}
		
	}
	
	/**
	 * 中序遍历
	 * @param index 根节点的索引
	 */
	private void infixOrder(int index) {
		//向左子节点递归遍历
		if((2*index+1)<arr.length) {
			infixOrder(2*index+1);
		}
		//输出当前节点
		System.out.println(arr[index]);
		//向右子节点递归遍历
		if((2*index+2)<arr.length) {
			infixOrder(2*index+2);
		}
	}
	
	/**
	 * 后序遍历
	 * @param index 根节点的索引
	 */
	private void postOrder(int index) {
		//向左子节点递归遍历
		if((2*index+1)<arr.length) {
			postOrder(2*index+1);
		}
		
		//向右子节点递归遍历
		if((2*index+2)<arr.length) {
			postOrder(2*index+2);
		}
		//输出当前节点
		System.out.println(arr[index]);
	}
}

线索化二叉树

在这里插入图片描述

  1. 如上,在含有n个节点的二叉链表中含有n+1个空指针域(上方3,4,5三个节点的左右指针域),利用二叉链表中的空指针域,存放指向节点在某种遍历次序下的前驱和后继节点的指针(这种附加的指针称作线索),即二叉树的线索化
  2. 这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树。根据线索性质的不同,可以分为前序线索二叉树、中序线索二叉树、后序线索二叉树三种
  3. 在遍历中,某个节点前一个遍历的节点称为前驱节点,后一个称为后继节点

示意图

在这里插入图片描述
如上,线索化二叉树之后,Node节点的left和right有两种情况:

  1. left指向的是左子树,也有可能是指向前驱节点,比如1节点的left指向左子树,而5节点的left指向前驱节点
  2. right指向的是右子树,也有可能指向后继节点,比如1节点的right指向的是右子树,而5节点的right指向的是后继节点

代码实现(中序线索化)

/***
 * 线索化二叉树
 * @author laowa
 *
 */
class ThreadBinaryTree{
	/**
	 * 根节点
	 */
	Node root;
	
	/**
	 * 为了实现线索化的辅助节点
	 * 因为二叉树是单向的,在进行线索化时,pre总是指向当前节点的前驱节点
	 */
	Node pre = null;

	public ThreadBinaryTree(Node root) {
		this.root = root;
	}
	
	/**
	 * 中序线索化二叉树
	 */
	public void infixThread() {
		infixThreadNodes(root);
	}
	
	/**
	 * 对节点进行中序线索化
	 * @param node 需要线索化的节点
	 */
	public void infixThreadNodes(Node node) {
		//判空,节点为null不能线索化
		if(node==null) {
			System.out.println("节点为空,不可线索化");
			return;
		}
		//1. 向左递归线索化
		if(node.left!=null) {
			infixThreadNodes(node.left);
		}
		
		//2. 线索化当前节点
		//如果当前节点的左指针为空,则将左指针指向前驱节点,然后将左指针的类型改为节点
		if(node.left==null) {
			node.left=pre;
			node.leftType = Node.NODE;
		}
		//如果当前节点的前驱节点的右指针为空,则将前驱节点的后继节点指向当前节点,并且将右指针类型改为节点
		if(pre!=null&&pre.right==null) {
			pre.right = node;
			pre.rightType = Node.NODE;
		}
		//每处理一个节点后,让pre指向当前节点,遍历到下一个节点后,pre就是前驱节点了
		pre = node;
		//3. 向右递归线索化
		if(node.right!=null) {
			infixThreadNodes(node.right);
		}
		
	}
}

/**
 * 树的节点
 * 
 * @author laowa
 *
 */
class Node {
	/**
	 * 表示指向子树
	 */
	public static final int CHILD_TREE=0;
	/**
	 * 表示指向前驱或后继节点
	 */
	public static final int NODE=1;
	int no;
	String name;
	/**
	 * 左子节点
	 */
	Node left;
	/**
	 * 右子节点
	 */
	Node right;
	/**
	 * 如果leftType为0,则表示指向的是左子树,如果leftType为1,表示指向前驱节点
	 */
	int leftType = Node.CHILD_TREE;
	/**
	 * 如果rihgtType为0,则表示指向的是右子树,如果rightType为1,表示指向的是后继节点
	 */
	int rightType = Node.CHILD_TREE;

	public Node(int no, String name) {
		this.no = no;
		this.name = name;
	}

	@Override
	public String toString() {
		return "[no=" + no + "\tname=" + name + "]";
	}

}

中序线索化二叉树的遍历

	/**
	 * 遍历中序线索化二叉树
	 */
	public void infixThreadList() {
		// 辅助节点帮助遍历
		Node helper = root;
		// 当helper节点为空时退出循环
		while (helper != null) {
			// 向左找,一直找到leftType为node的节点,该节点就是最左侧叶子节点
			while (helper.leftType == Node.CHILD_TREE) {
				helper = helper.left;
			}
			// 输出当前节点
			System.out.println(helper);
			// 一直向右沿着线索化遍历,直到下一个节点的right非线索化
			while (helper.rightType == Node.NODE) {
				helper = helper.right;
				System.out.println(helper);
			}
			// 当前节点的right非线索化,说明该节点不是叶子节点,且左侧的叶子节点已经遍历完了,直接向右移动一位
			helper = helper.right;
		}
	}

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

/***
 * 线索化二叉树
 * 
 * @author laowa
 *
 */
class ThreadBinaryTree {
	/**
	 * 根节点
	 */
	Node root;

	/**
	 * 为了实现线索化的辅助节点 因为二叉树是单向的,在进行线索化时,pre总是指向当前节点的前驱节点
	 */
	Node pre = null;

	public ThreadBinaryTree(Node root) {
		this.root = root;
	}

	/**
	 * 中序线索化二叉树
	 */
	public void infixThread() {
		infixThreadNodes(root);
	}

	/**
	 * 前序线索化二叉树
	 */
	public void preThread() {
		preThreadNodes(root);
	}

	/**
	 * 后序线索化二叉树
	 */
	public void postThread() {
		postThreadNodes(root);
	}

	/**
	 * 遍历中序线索化二叉树
	 */
	public void infixThreadList() {
		// 辅助节点帮助遍历
		Node helper = root;
		// 当helper节点为空时退出循环
		while (helper != null) {
			// 向左找,一直找到leftType为node的节点,该节点就是最左侧叶子节点
			while (helper.leftType == Node.CHILD_TREE) {
				helper = helper.left;
			}
			// 输出当前节点
			System.out.println(helper);
			// 一直向右沿着线索化遍历,直到下一个节点的right非线索化
			while (helper.rightType == Node.NODE) {
				helper = helper.right;
				System.out.println(helper);
			}
			// 当前节点的right非线索化,说明该节点不是叶子节点,且左侧的叶子节点已经遍历完了,直接向右移动一位
			helper = helper.right;
		}
	}

	/**
	 * 遍历先序线索化二叉树
	 */
	public void preThreadList() {
		// 辅助节点帮助遍历
		Node helper = root;
		// 当helper节点为空时停止遍历
		while (helper != null) {
			// 当左节点不为叶子节点时,先输出,然后左移
			while (helper.leftType != Node.NODE) {
				System.out.println(helper);
				helper = helper.left;
			}
			// 循环结束后到了最左侧的叶子节点,输出当前节点
			System.out.println(helper);
			// 根据线索化,依次遍历节点
			while (helper.rightType == Node.NODE) {
				helper = helper.right;
				System.out.println(helper);
			}
			// 当当前节点的right非线索化
			helper = helper.right;
		}
	}

	/**
	 * 遍历后序线索化二叉树
	 */
	public void postThreadList() {
		postListNode(root);
	}
	
	/**
	 * 遍历后序线索化节点
	 * @param node
	 */
	private void postListNode(Node node) {
		//向左递归直到叶子节点
		if(node.leftType==Node.CHILD_TREE) {
			postListNode(node.left);
		}
		//向右递归直到叶子节点
		if(node.rightType==Node.CHILD_TREE) {
			postListNode(node.right);
		}
		//输出当前节点
		System.out.println(node);
		
	}

	/**
	 * 对节点进行中序线索化
	 * 
	 * @param node
	 *            需要线索化的节点
	 */
	public void infixThreadNodes(Node node) {
		// 判空,节点为null不能线索化
		if (node == null) {
			return;
		}
		// 1. 向左递归线索化
		infixThreadNodes(node.left);

		// 2. 线索化当前节点
		// 如果当前节点的左指针为空,则将左指针指向前驱节点,然后将左指针的类型改为节点
		if (node.left == null) {
			node.left = pre;
			node.leftType = Node.NODE;
		}
		// 如果当前节点的前驱节点的右指针为空,则将前驱节点的后继节点指向当前节点,并且将右指针类型改为节点
		if (pre != null && pre.right == null) {
			pre.right = node;
			pre.rightType = Node.NODE;
		}
		// 每处理一个节点后,让pre指向当前节点,遍历到下一个节点后,pre就是前驱节点了
		pre = node;
		// 3. 向右递归线索化
		infixThreadNodes(node.right);
	}

	/**
	 * 对节点进行前序线索化
	 * 
	 * @param node
	 *            待线索化的节点
	 */
	public void preThreadNodes(Node node) {
		// 判空
		if (node == null) {
			return;
		}
		//标志量,如果当前进行了左指针的线索化则不在向左递归
		boolean toLeft = true;
		//标志量,如果当前进行了右指针的线索化则不再向右递归
		boolean toRight = true;
		// 1.将当前节点线索化
		if (node.left == null) {
			node.left = pre;
			node.leftType = Node.NODE;
			toLeft = false;
		}
		if (pre != null && pre.right == null) {
			pre.right = node;
			pre.rightType = Node.NODE;
			toRight = false;
		}
		pre = node;
		// 2.向左递归线索化
		if (toLeft) {
			preThreadNodes(node.left);
		}
		// 3.向右递归线索化
		if(toRight) {
			preThreadNodes(node.right);
		}
		
	}

	/**
	 * 对节点进行后序线索化
	 * 
	 * @param node
	 *            待线索化的节点
	 */
	public void postThreadNodes(Node node) {
		// 判空
		if (node == null) {
			return;
		}
		// 1.向左递归线索化
		postThreadNodes(node.left);

		// 2.向右递归线索化
		postThreadNodes(node.right);
		// 3.将当前节点线索化
		if (node.left == null) {
			node.left = pre;
			node.leftType = Node.NODE;
		}
		if (pre != null && pre.right == null) {
			pre.right = node;
			pre.rightType = Node.NODE;
		}
		pre = node;
	}
}

/**
 * 树的节点
 * 
 * @author laowa
 *
 */
class Node {
	/**
	 * 表示指向子树
	 */
	public static final int CHILD_TREE = 0;
	/**
	 * 表示指向前驱或后继节点
	 */
	public static final int NODE = 1;
	int no;
	String name;
	/**
	 * 左子节点
	 */
	Node left;
	/**
	 * 右子节点
	 */
	Node right;
	/**
	 * 如果leftType为0,则表示指向的是左子树,如果leftType为1,表示指向前驱节点
	 */
	int leftType = Node.CHILD_TREE;
	/**
	 * 如果rihgtType为0,则表示指向的是右子树,如果rightType为1,表示指向的是后继节点
	 */
	int rightType = Node.CHILD_TREE;

	public Node(int no, String name) {
		this.no = no;
		this.name = name;
	}

	@Override
	public String toString() {
		return "[no=" + no + "\tname=" + name + "]";
	}

}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-23 11:02:21  更:2022-04-23 11:04:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 8:32:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码