数据结构(七)---二叉树
树的基本介绍
树分成两部分:基础部分+应用部分
(一)基础部分
1)数组存储方式的分析
有点:可以通过下标访问元素,速度快,对于有序数组,还可以使用二分查找提高检索速度
缺点:如果要检索某个具体的值,或者插入值,会导致整体移动,效率很低
2)链式存储方式的分析
优点:插入删除节点时,不会导致整体移动,效率比数组要好
缺点:再检索时,不如有索引的数组块,需要从头开始遍历
3)树存储方式的分析
优点:能提高数据的存储、读取的效率,比如利用二叉排序树,既可以保证数据的检索速度,同时保证数据的插入、删除、修改的速度
如果用“二叉排序树”来存储数据,那么对数据的增删改查的效率都可以提高
(二)二叉树遍历
1)创建一颗二叉树
2)前序遍历
2.1)先输出当前节点(初始的时候是root节点)
2.2)如果左子节点不为空,则递归继续前序遍历
2.3)如果右子节点不为空,则递归继续前序遍历
3)中序遍历
3.1)如果左子节点不为空,则递归继续前序遍历
3.2)输出当前节点
3.3)如果右子节点不为空,则递归继续前序遍历
4)后序遍历
4.1)如果左子节点不为空,则递归继续前序遍历
4.2)如果右子节点不为空,则递归继续前序遍历
4.3)输出当前节点
(三)使用前序、中序、后序的方式来查询指定的结点
前序查找思路:
1)先判断当前节点的no是否是要查找的
2)如果是相等,则返回当前结点
3)如果不相等,则判断当前结点的左子节点是否为空,如果不为空,则递归前序查找
4)如果左递归前序查找,找到节点,则返回,否则继续判断,当前的节点的右子节点是否为空,
如果不空,则继续向右递归前序查找
中序查找思路:
1)先判断当前结点的左子节点是否为空,如果不为空,则递归前序查找
2)如果找到,则返回,如果没有找到,就和当前结点比较,如果是则返回当前结点,否则继续进行右递归的中序查找
3)如果右递归中序查找,找到就返回,找到就返回,否则返回null
后序查找思路:
1)判断当前结点的左子节点是否为空,如果不为空,则递归后续查找
2)如果找到,就返回,如果没有找到,就判断当前结点的右子节点是否为空,如果不为空,则右递归进行后序查找,如果找到,就返回
3)就和当前结点进行,比如,如果是则返回,否则返回null
(四)删除二叉树的结点
规定:
1)如果删除的结点是叶子结点,则删除该节点
2)如果删除的节点是非叶子界定啊,则删除该子树
思路:(判断的不是当前节点,而是当前节点的左右子节点)
首先处理:考虑如果树是空树root,如果只有一个root节点,则等价把二叉树置空
1)因为我们的二叉树是单向的,所以我们是判断当前节点的子节点是否是待删除的节点
而不能去判断当前节点是不是待删除的节点
2)如果当前节点的左子节点不为空,并且左子节点就是待删除的节点,就把this.left=null,把左子树置为空
3)如果当前节点的右子节点不为空,并且右子节点就是待删除的节点,就把this.right=null,把右子树置为空
4)如果2,3两步都没有删除节点,那就需要向左子树进行递归删除
5)如果4步向左子树递归删除也没有删除成功,那就需要向右子树进行递归删除
(五)顺序存储二叉树(堆排序就会用到顺序存储二叉树)
基本说明:
从数据存储来看,数组存储方式和树的存储方式可以相互转换,就是说数组可以转换成树,树叶可以转换成数组
要求:
1)二叉树的节点,要求以数组的方式来存放arr
2)要求在遍历数组arr时,仍然可以以前序遍历,中序遍历和后序遍历的方式完成节点的遍历
需要熟悉二叉树的特点:
1)顺序二叉树通常只考虑完全二叉树
2)第n个元素的左子节点为2n+1
3)第n个元素的右子节点为2n+2
4)第n个元素的父节点为(n-1)/2
5)n:表示二叉树中的第几个元素(按0开始编号)
(六)线索化二叉树
问题分析:
1)当我们对上面的二叉树进行中序遍历时
2)但是好几个节点的左右指针,并没有完全的利用上
3)如果我们希望充分的利用各个节点的左右指针,让各个节点可以指向自己的前后节点怎么办?
4)解决方法就是使用——线索二叉树
线索二叉树的介绍:
1)n个节点的二叉链表中含有n+1个空指针域。如果在这些空指针域中存放指向节点的前驱和后继节点的指针,就可以充分利用
2)二叉链表加上线索(前驱后继指针)==》线索链表,二叉树加上线索就成了线索二叉树
分成:1-前序线索二叉树,2-中序线索二叉树,3-后序线索二叉树
3)一个节点的前一个节点,叫前驱节点
4)一个节点的后一个节点,叫后继节点
思路分析:
比如说中序线索二叉树,先写出来二叉树的中序遍历{8,3,10,1,14,6}
然后根据中序遍历,在二叉树里找到前后关系,画上线索表示前驱和后继
特点说明:
1)left指向的是左子树,也可能是指向的前驱节点
2)right指向的右子树,也可能是指向后继节点
(七)遍历线索化二叉树
说明:对中序线索化的二叉树进行遍历
分析:线索化后,各个节点指向有变化,因此原来的遍历方式不能再用了
这时候要用新的的方式遍历线索化二叉树,各个节点可以通过线型方式遍历
因此,不需要使用递归方式,也就提高了遍历的效率,遍历的次序应当和中序遍历保持一致
(八)堆排序的基本思想
1)把待排序序列构造成一个大顶堆
2)此时,整个序列的最大值就是堆顶的根节点
3)把其与末尾元素进行交换,此时末尾就为最大值
4)然后把剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,就能得到一个有序序列了
举例:{4,6,8,5,9}
1)首先,有一个无序序列结构,在这个基础上进行排序
2)此时我们从最后一个非叶子节点开始(叶子节点不需要调整),从左至右,从上至下进行调整
第一个非叶子节点怎么得来的呢——arr.length/2-1=5/2-1=1
3)编号为1的非叶子节点,假设为6,把6和6的左右子节点(也就是叶子节点)进行比较,
如果6比左右子节点都大,就不需要调整
如果6比右子节点小,那就应该把6和右子节点互换位置
如果6比左右子节点都小,那就应该和最大的那个进行交换
4)接着找第二个非叶子节点,继续进行交换
交换过后,会出现一种情况,新的节点位置可能会影响下面子树的结构
这时候,继续调整
5)到最后,最大的值会移动到根节点的位置
把根节点和树末尾的值交换位置,然后取出这个最大值
前中后遍历二叉树
创建节点类
//先创建节点
class HeroNode {
private int no;
private String name;
private HeroNode left;
private HeroNode right;
//构造器
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
//编写递归删除的方法
//如果删除的节点是叶子节点,就删除该节点
//如果删除的节点是非叶子节点,就删除该子树
public void delNode(int no) {
// 思路:(判断的不是当前节点,而是当前节点的左右子节点)
// 首先处理:考虑如果树是空树root,如果只有一个root节点,则等价把二叉树置空
// 1)因为我们的二叉树是单向的,所以我们是判断当前节点的子节点是否是待删除的节点
// 而不能去判断当前节点是不是待删除的节点
// 2)如果当前节点的左子节点不为空,并且左子节点就是待删除的节点,就把this.left=null,把左子树置为空
if (this.left != null && this.left.no == no) {
this.left = null;
return;
}
// 3)如果当前节点的右子节点不为空,并且右子节点就是待删除的节点,就把this.right=null,把右子树置为空
if (this.right != null && this.right.no == no) {
this.right = null;
return;
}
// 4)如果2,3两步都没有删除节点,那就需要向左子树进行递归删除
if (this.left != null) {
this.left.delNode(no);
}
// 5)如果4步向左子树递归删除也没有删除成功,那就需要向右子树进行递归删除
if (this.right != null) {
this.right.delNode(no);
}
}
//编写前序遍历的方法
public void preOrder() {
//先输出当前节点
System.out.println(this);
//再输出左子节点(递归)——递归向左子树前序遍历
if (this.left != null) {
this.left.preOrder();
}
//最后输出右子节点(递归)——递归向右子树前序遍历
if (this.right != null) {
this.right.preOrder();
}
}
//编写中序遍历的方法
public void infixOrder() {
//输出左子节点(递归)——递归向左子树中序遍历
if (this.left != null) {
this.left.infixOrder();
}
//输出父节点
System.out.println(this);
//输出右子节点(递归)——递归向右子树中序遍历
if (this.right != null) {
this.right.infixOrder();
}
}
//编写后序遍历的方法
public void postOrder() {
//输出左子节点(递归)——递归向左子树后序遍历
if (this.left != null) {
this.left.postOrder();
}
//输出右子节点(递归)——递归向右子树后序遍历
if (this.right != null) {
this.right.postOrder();
}
//输出父节点
System.out.println(this);
}
//
/**
* 前序遍历查找
* 如果找到就返回该Node,如果没有找到返回null
*
* @MethodName: preOrderSearch
* @Author: AllenSun
* @Date: 2019/11/4 23:24
*/
public HeroNode preOrderSearch(int no) {
System.out.println("进入前序遍历");//这句话用来统计一共进行了几次前序遍历
//比较当前结点是不是要找的节点
if (this.no == no) {
return this;
}
//1-则判断当前结点的左子节点是否为空,如果不为空,则递归前序查找
//2-如果左递归前序查找,找到节点,则返回
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.preOrderSearch(no);
}
if (resNode != null) {
//说明我们左子树找到,得到节点,则返回,否则继续判断
return resNode;
}
//如果左递归没有找到,就判断判断当前结点的右子节点是否为空,如果不为空,则继续向右递归前序查找
if (this.right != null) {
resNode = this.right.preOrderSearch(no);
}
return resNode;
}
/**
* 中序遍历查找
*
* @MethodName:
* @Author: AllenSun
* @Date: 2019/11/4 23:41
*/
public HeroNode infixOrderSearch(int no) {
//判断当前结点的左子节点是否为空,如果不为空,则递归中序查找
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.infixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
System.out.println("进入中序遍历");//这句话用来统计一共进行了几次中序遍历
//如果找到,则返回,如果没有找到,就和当前结点比较,如果是则返回当前结点
if (this.no == no) {
return this;
}
//否则继续进行右递归的中序查找
if (this.right != null) {
resNode = this.right.infixOrderSearch(no);
}
return resNode;
}
/**
* 后序遍历
*
* @MethodName:
* @Author: AllenSun
* @Date: 2019/11/4 23:59
*/
public HeroNode postOrderSearch(int no) {
//判断当前结点左子节点是否为空,如果不为空,则递归后序查找
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.postOrderSearch(no);
}
if (resNode != null) {//说明在左子树找到
return resNode;
}
//如果左子树没有找到,那就到右子树去找递归查找
if (this.right != null) {
resNode = this.right.postOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
System.out.println("进入后序遍历");//这句话用来统计一共进行了几次后序遍历
//如果左右子树都没有找到,那就比较当前的节点
if (this.no == no) {
return this;
}
return resNode;
}
}
创建一个树类
//创建一个树
class BinaryTree {
private HeroNode root;//根节点
public void setRoot(HeroNode root) {
this.root = root;
}
//删除节点
public void delNode(int no){
if(root!=null){
//如果只有根节点,这里理解判断root是不是就是要删除节点
if(root.getNo()==no){
root=null;
} else {
//递归删除
root.delNode(no);
}
} else {
System.out.println("空树,不能删除");
}
}
//前序遍历
public void preOrder() {
if (this.root != null) {
this.root.preOrder();
} else {
System.out.println("二叉树为空,无法遍历");
}
}
//中序遍历
public void infixOrder() {
if (this.root != null) {
this.root.infixOrder();
} else {
System.out.println("二叉树为空,无法遍历");
}
}
//后序遍历
public void postOrder() {
if (this.root != null) {
this.root.postOrder();
} else {
System.out.println("二叉树为空,无法遍历");
}
}
//前序遍历查找
public HeroNode preOrderSearch(int no) {
if (root != null) {
return root.preOrderSearch(no);
} else {
return null;
}
}
//中序遍历查找
public HeroNode infixOrderSearch(int no) {
if (root != null) {
return root.infixOrderSearch(no);
} else {
return null;
}
}
//后序遍历查找
public HeroNode postOrderSearch(int no) {
if (root != null) {
return root.postOrderSearch(no);
} else {
return null;
}
}
}
测试类
public class BinaryTreeDemo {
public static void main(String[] args) {
//先需要创建一颗二叉树
BinaryTree binaryTree = new BinaryTree();
//创需要的节点
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢俊义");
HeroNode node4 = new HeroNode(4, "林冲");
HeroNode node5 = new HeroNode(5, "关胜");
//说明,我们先手动创建二叉树,后面我们学习递归的方式创建二叉树
binaryTree.setRoot(root);//设置根节点
root.setLeft(node2);//设置左子树
root.setRight(node3);
node3.setRight(node4);
node3.setLeft(node5);
//测试一下前中后遍历
System.out.println("前序遍历:");
binaryTree.preOrder();
System.out.println("中序遍历:");
binaryTree.infixOrder();
System.out.println("后序遍历:");
binaryTree.postOrder();
//前序遍历查找
//前序遍历的次数:4次
System.out.println("前序遍历方式");
HeroNode resNode01 = binaryTree.preOrderSearch(5);
if (resNode01 != null) {
System.out.printf("找到了,信息为no=%d name=%s\n", resNode01.getNo(), resNode01.getName());
} else {
System.out.printf("没有找到信息为no=%d name=%s 的英雄\n", resNode01.getNo(), resNode01.getName());
}
//中序遍历查找
//中序遍历的次数:3次
System.out.println("中序遍历方式");
HeroNode resNode02 = binaryTree.infixOrderSearch(5);
if (resNode02 != null) {
System.out.printf("找到了,信息为no=%d name=%s\n", resNode02.getNo(), resNode02.getName());
} else {
System.out.printf("没有找到信息为no=%d name=%s 的英雄\n", resNode02.getNo(), resNode02.getName());
}
//后序遍历查找
//后序遍历的次数:2次
System.out.println("后序遍历方式");
HeroNode resNode03 = binaryTree.postOrderSearch(5);
if (resNode03 != null) {
System.out.printf("找到了,信息为no=%d name=%s\n", resNode03.getNo(), resNode03.getName());
} else {
System.out.printf("没有找到信息为no=%d name=%s 的英雄\n", resNode03.getNo(), resNode03.getName());
}
//测试一把删除节点
System.out.println("删除前,前序遍历");
binaryTree.preOrder();
binaryTree.delNode(5);
System.out.println("删除后,前序遍历");
binaryTree.preOrder();
}
}
顺序存储二叉树
编写一个ArrayBinaryTree,实现顺序存储二叉树遍历
//编写一个ArrayBinaryTree,实现顺序存储二叉树遍历
class ArrBinaryTree {
private int arr[];//存储数据节点的数组
public ArrBinaryTree(int arr[]) {
this.arr = arr;
}
//重载preOrder
public void preOrder(){
this.preOrder(0);
}
//编写一个方法,完成顺序存储二叉树的前序遍历
public void preOrder(int index) {
//如果数组为空,或者arr.length=0
if (arr == null || arr.length == 0) {
System.out.println("数组为空,不能按照二叉树的前序遍历");
}
System.out.print(arr[index]+"\t");//输出当前的元素
//向左递归遍历
if ((index * 2 + 1) < arr.length) {
preOrder(2 * index + 1);
}
//向右递归遍历
if ((index * 2 + 2) < arr.length) {
preOrder(2 * index + 2);
}
}
}
测试类
public class ArrBinaryTreeDemo {
public static void main(String[] args) {
int arr[] = {1, 2, 3, 4, 5, 6, 7};
//创建一个ArrBinaryTree
ArrBinaryTree arrBinaryTree = new ArrBinaryTree(arr);
arrBinaryTree.preOrder(0);//1,2,4,5,3,6,7
}
}
线索二叉树
创建节点类
//创建节点HeroNode
class HeroNode {
private int no;
private String name;
private HeroNode left;
private HeroNode right;
//线索二叉树说明
//1-如果leftType==0 表示指向的是左子树,如果1则表示指向前驱节点
//2-如果rightType==0 表示指向的是右子树,如果1则表示指向后继节点
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 HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
//编写递归删除的方法
//如果删除的节点是叶子节点,就删除该节点
//如果删除的节点是非叶子节点,就删除该子树
public void delNode(int no) {
// 思路:(判断的不是当前节点,而是当前节点的左右子节点)
// 首先处理:考虑如果树是空树root,如果只有一个root节点,则等价把二叉树置空
// 1)因为我们的二叉树是单向的,所以我们是判断当前节点的子节点是否是待删除的节点
// 而不能去判断当前节点是不是待删除的节点
// 2)如果当前节点的左子节点不为空,并且左子节点就是待删除的节点,就把this.left=null,把左子树置为空
if (this.left != null && this.left.no == no) {
this.left = null;
return;
}
// 3)如果当前节点的右子节点不为空,并且右子节点就是待删除的节点,就把this.right=null,把右子树置为空
if (this.right != null && this.right.no == no) {
this.right = null;
return;
}
// 4)如果2,3两步都没有删除节点,那就需要向左子树进行递归删除
if (this.left != null) {
this.left.delNode(no);
}
// 5)如果4步向左子树递归删除也没有删除成功,那就需要向右子树进行递归删除
if (this.right != null) {
this.right.delNode(no);
}
}
//编写前序遍历的方法
public void preOrder() {
//先输出当前节点
System.out.println(this);
//再输出左子节点(递归)——递归向左子树前序遍历
if (this.left != null) {
this.left.preOrder();
}
//最后输出右子节点(递归)——递归向右子树前序遍历
if (this.right != null) {
this.right.preOrder();
}
}
//编写中序遍历的方法
public void infixOrder() {
//输出左子节点(递归)——递归向左子树中序遍历
if (this.left != null) {
this.left.infixOrder();
}
//输出父节点
System.out.println(this);
//输出右子节点(递归)——递归向右子树中序遍历
if (this.right != null) {
this.right.infixOrder();
}
}
//编写后序遍历的方法
public void postOrder() {
//输出左子节点(递归)——递归向左子树后序遍历
if (this.left != null) {
this.left.postOrder();
}
//输出右子节点(递归)——递归向右子树后序遍历
if (this.right != null) {
this.right.postOrder();
}
//输出父节点
System.out.println(this);
}
//
/**
* 前序遍历查找
* 如果找到就返回该Node,如果没有找到返回null
*
* @MethodName: preOrderSearch
* @Author: AllenSun
* @Date: 2019/11/4 23:24
*/
public HeroNode preOrderSearch(int no) {
System.out.println("进入前序遍历");//这句话用来统计一共进行了几次前序遍历
//比较当前结点是不是要找的节点
if (this.no == no) {
return this;
}
//1-则判断当前结点的左子节点是否为空,如果不为空,则递归前序查找
//2-如果左递归前序查找,找到节点,则返回
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.preOrderSearch(no);
}
if (resNode != null) {
//说明我们左子树找到,得到节点,则返回,否则继续判断
return resNode;
}
//如果左递归没有找到,就判断判断当前结点的右子节点是否为空,如果不为空,则继续向右递归前序查找
if (this.right != null) {
resNode = this.right.preOrderSearch(no);
}
return resNode;
}
/**
* 中序遍历查找
*
* @MethodName:
* @Author: AllenSun
* @Date: 2019/11/4 23:41
*/
public HeroNode infixOrderSearch(int no) {
//判断当前结点的左子节点是否为空,如果不为空,则递归中序查找
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.infixOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
System.out.println("进入中序遍历");//这句话用来统计一共进行了几次中序遍历
//如果找到,则返回,如果没有找到,就和当前结点比较,如果是则返回当前结点
if (this.no == no) {
return this;
}
//否则继续进行右递归的中序查找
if (this.right != null) {
resNode = this.right.infixOrderSearch(no);
}
return resNode;
}
/**
* 后序遍历
*
* @MethodName:
* @Author: AllenSun
* @Date: 2019/11/4 23:59
*/
public HeroNode postOrderSearch(int no) {
//判断当前结点左子节点是否为空,如果不为空,则递归后序查找
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.postOrderSearch(no);
}
if (resNode != null) {//说明在左子树找到
return resNode;
}
//如果左子树没有找到,那就到右子树去找递归查找
if (this.right != null) {
resNode = this.right.postOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
System.out.println("进入后序遍历");//这句话用来统计一共进行了几次后序遍历
//如果左右子树都没有找到,那就比较当前的节点
if (this.no == no) {
return this;
}
return resNode;
}
}
创建一个线索二叉树,实现了线索化功能的二叉树
//创建一个线索二叉树,实现了线索化功能的二叉树
class ThreadedBinaryTree {
private HeroNode root;//根节点
public void setRoot(HeroNode root) {
this.root = root;
}
//为了实现线索化,需要创建要给指向当前节点的前驱节点的指针
//在递归进行线索化时,pre 总是保留前一个节点
private HeroNode pre = null;
//重载一把threadedNodes方法
public void threadedNodes() {
this.threadedNodes(root);
}
//遍历线索化二叉树的方法
public void threadedList() {
//定义一个变量,存储当前遍历的节点,从root开始
HeroNode node = root;
while (node != null) {
//循环的找到leftType==1的节点,第一个找到就是8节点
//后面随着遍历而变化,因为当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();
}
}
//编写对二叉树进行中序线索化的方法
public void threadedNodes(HeroNode node) {
//如果node==null,不能线索化
if (node == null) {
return;
}
//(一)先线索化左子树
threadedNodes(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 = node;
//(三)再线索化右子树
threadedNodes(node.getRight());
}
//删除节点
public void delNode(int no) {
if (root != null) {
//如果只有根节点,这里理解判断root是不是就是要删除节点
if (root.getNo() == no) {
root = null;
} else {
//递归删除
root.delNode(no);
}
} else {
System.out.println("空树,不能删除");
}
}
//前序遍历
public void preOrder() {
if (this.root != null) {
this.root.preOrder();
} else {
System.out.println("二叉树为空,无法遍历");
}
}
//中序遍历
public void infixOrder() {
if (this.root != null) {
this.root.infixOrder();
} else {
System.out.println("二叉树为空,无法遍历");
}
}
//后序遍历
public void postOrder() {
if (this.root != null) {
this.root.postOrder();
} else {
System.out.println("二叉树为空,无法遍历");
}
}
//前序遍历查找
public HeroNode preOrderSearch(int no) {
if (root != null) {
return root.preOrderSearch(no);
} else {
return null;
}
}
//中序遍历查找
public HeroNode infixOrderSearch(int no) {
if (root != null) {
return root.infixOrderSearch(no);
} else {
return null;
}
}
//后序遍历查找
public HeroNode postOrderSearch(int no) {
if (root != null) {
return root.postOrderSearch(no);
} else {
return null;
}
}
}
测试类
public class ThreadedBinaryTreeDemo {
public static void main(String[] args) {
//测试一下中序线索二叉树的功能
HeroNode root = new HeroNode(1, "tom");
HeroNode node2 = new HeroNode(3, "jack");
HeroNode node3 = new HeroNode(6, "smith");
HeroNode node4 = new HeroNode(8, "marry");
HeroNode node5 = new HeroNode(10, "king");
HeroNode node6 = new HeroNode(14, "dim");
//手动创建二叉树
root.setLeft(node2);
root.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
//测试线索化
ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree();
threadedBinaryTree.setRoot(root);
threadedBinaryTree.threadedNodes();
//测试:以10号节点测试
HeroNode leftNode = node5.getLeft();
HeroNode rightNode = node5.getRight();
System.out.println("10号节点的前驱节点是:" + leftNode);
System.out.println("10号节点的后继节点是:" + rightNode);
//当线索化二叉树后,能在使用原来的遍历方法
System.out.println("使用线索化的方式遍历线索化二叉树");
threadedBinaryTree.threadedList();
}
}