这一节,完成以下任务:
- 编写前序、中序、后序查找的方法。
- 使用三种方式,查找no为5的结点。
- 分析每种查找方式,分别比较了几次。
一、思路
与前面遍历的思路类似,直接上思路图解:
以 5号节点为例,不同顺序的查找方式,比较次数是不一样的。
前序需要4次比较才能找到5号节点,中序3次,后序2次。
二、代码
1、三种查找底层代码
// 前序遍历查找
/**
* @param no 查找no
* @return 找到就返回该Node,否则返回null
*/
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;
}
// 1.左递归前序查找,找到结点,则返回,否则继续判断,
// 2.当前结点的右子节点是否为空,如果不为空,则继续向右递归前序查找。
if (this.right != null) {
resNode = this.right.preOrderSearch(no);
}
return resNode;
}
// 中序遍历查找
public HeroNode midOrderSearch(int no) {
// 判断当前结点的左子节点是否为空,如果不为空,则递归中序查找。
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.midOrderSearch(no);
}
if (resNode != null) {
return resNode;
}
System.out.println("进入中序查找~");
// 如果找到,则返回,如果没找到,就和当前结点比较,如果是则返回当前结点
if (this.no == no) {
return this;
}
// 否则,向右进行右递归的中序查找
if (this.right != null) {
resNode = this.right.midOrderSearch(no);
}
return resNode;
}
// 后序遍历查找
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;
}
2、BinaryTree类中调用代码
// 前序遍历查找
public HeroNode preOrderSearch(int no) {
if (root != null) {// 至少有一个结点
return root.preOrderSearch(no);
} else {
return null;
}
}
// 中序遍历查找
public HeroNode midOrderSearch(int no) {
if (root != null) {
return root.midOrderSearch(no);
} else {
return null;
}
}
// 后序遍历查找
public HeroNode postOrderSearch(int no) {
if (root != null) {
return root.postOrderSearch(no);
} else {
return null;
}
}
3、测试代码
// 测试前序遍历查找
// 前序遍历为5的次数: 4
System.out.println("这是前序查找方式~~");
HeroNode resNode = binaryTree.preOrderSearch(5);
if (resNode != null) {
System.out.printf("找到了,信息为no=%d name=%s\n", resNode.getNo(), resNode.getName());
} else {
System.out.printf("没有找到 no = %d 的英雄", 5);
}
// 测试中序遍历查找
// 中序遍历为5的次数: 3
System.out.println("这是中序查找方式~~");
HeroNode resNode1 = binaryTree.midOrderSearch(5);
if (resNode1 != null) {
System.out.printf("找到了,信息为no=%d name=%s\n", resNode1.getNo(), resNode1.getName());
} else {
System.out.printf("没有找到 no = %d 的英雄", 5);
}
// 测试后序遍历查找
// 后序遍历为5的次数: 2
System.out.println("这是后序查找方式~~");
HeroNode resNode2 = binaryTree.postOrderSearch(5);
if (resNode2 != null) {
System.out.printf("找到了,信息为no=%d name=%s\n", resNode2.getNo(), resNode2.getName());
} else {
System.out.printf("没有找到 no = %d 的英雄", 5);
}
输出结果:
值得注意的是,测试进行了几次比较时,需要在进行比较的语句前加上输出测试语句,因为用到了递归,例如后序遍历查找:前面都是判断是否为空,后面才是判断是否相等。
后序比较流程:1 的左子节点是否为空,不为空,进入左递归。再判断左子是否为空,为空,退出;判断右子是否为空,为空,退出。开始进行比较2和5(比较次数+1)。
左子树遍历结束,没有找到。结束比较,返回上一个栈,右子树不为空,调用后序递归,又开始比较3的左子树是否为空,不为空,进入后序递归,比较5的左子树是否为空,为空,退出;判断右子树是否为空,为空,退出。开始进行比较5和5(比较次数+1)
小结:不难看出,判断为空有多次,而判断是否相等只有2次。