可以把遍历的递归看成两部分
一个是左递归 一个是右递归 两者互不打扰 各自递归各自
而不是我理解的 先递归了左边后 左边的再依次往上爬 再向右边
我不理解的一点 从A开始 一直左递归 所以打印了C之后 怎么会打印D(D是右子树)
这是因为 到B结点 在经历了sout 左递归后 会 再进行右递归 就打印了D 所以还是一个思想各个结点的递归互不干涉
代码
/**
* title: 前中后序查找
* @author 阿K
* 2020年12月30日 下午11:49:44
*/
public class BinaryTreeDemo2 {
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, "关胜");
// 加入树
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
node3.setLeft(node5);
binaryTree.setRoot(root);
System.out.println("前序遍历,预计统计次数:4 ===> 查找顺序 1,2,3,5,4");
binaryTree.perOrderSearch(5);
System.out.println("中序遍历,预计统计次数:3 ===》 查找顺序 2,1,5,3,4");
binaryTree.infixOrderSearch(5);
//
System.out.println("后序遍历,预计统计次数:2 ===》 查找顺序 2,5, 4,3,1");
binaryTree.postOrderSearch(5);
}
}
// 定义二叉树
class BinaryTree {
private HeroNode root;// 根节点
public void setRoot(HeroNode root) {
this.root = root;
}
// 前序遍历查找
public HeroNode perOrderSearch(int no) {
if (root != null) {
return root.perOrderSearch(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;
}
}
}
// 定义节点
class HeroNode {
private int no;
private String name;
private HeroNode left; // 左节点(默认为null)
private HeroNode right; // 右节点(默认为null)
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
/**
* 须知:关于查找次数的统计
* 为了有效的统计出正确的次数,应该放在 if(this.no == no) 上面
* @param no
* @return
*/
// 节点的前序遍历查找
public HeroNode perOrderSearch(int no) {//这里没有用static 这是因为否则就不能调用this了
System.out.println("记录前序遍历查找,打印次数决定查找运行次数!");//前序遍历先打印
// 比较当前节点是否
if (this.no == no) {//先比较结点的序号 这个就是前序遍历的第一步 打印第一个访问到的结点的信息 这里替换成了return
return this;
}
// 1、判断当前节点的左子节点是否为空,若不为空,则左递归前序查找
// 2、若左递归前序查找,找到节点则返回
HeroNode resNode = null;
if (this.left != null) {//this指的是当前遍历到的结点 这个this的初值指的是根节点
resNode = this.left.perOrderSearch(no);
}
if (resNode != null) {// 说明在左子树上找到了 如果经过上一个if语句
// 上一个if语句结束 代表已经找到了最底部的左字节点
//如果resNode是null
/*
代表这一步的resNode根本没被赋值 就是说根本没找到
if (this.left != null) {
resNode = this.left.perOrderSearch(no);
}
注意 调用perOrderSearch方法就是步进 因为每一次都是this.left调用 下一次就是this.this.left 这就是步进
如果某次的this.left满足了这个条件
if (this.no == no) {//先比较结点的序号 这个就是前序遍历的第一步 打印第一个访问到的结点的信息 这里替换成了return
return this;
}
那么就会返回this 然后resNode就会得到this的值了
如果不满足这个条件
if (this.no == no) {//先比较结点的序号 这个就是前序遍历的第一步 打印第一个访问到的结点的信息 这里替换成了return
return this;
}
也就是把从根节点的整个左子树都遍历完了 都没找到和指定序号相等的结点的序号 那么该方法也不会进入return 也就是说resNode不会被赋值(注意这个方法的最后是return resNode) 还是原来的null
*/
return resNode;
}
//经过上面的两个if 此时的resNode就变成了树的最底层的左子节点
//问题 那么在递归使用perOrderSearch的 时候 下面的代码不会执行吗
//注意 只有在左递归结束的时候 perOrderSearch函数才会执行下面的右循环 因为一直进入了循环就无法向下执行了
//错误了 并不是左递归结束才进行右递归 而是各个结点的递归是独立的 每次的左递归当然会进行右递归
// 1、当前节点的右子树是否为空,若不为空,则右递归前序查找
// 2、若右递归前序查找,找到节点则返回
if (this.right != null) {
//这个是查看右结点符不符合我们的编号
resNode = this.right.perOrderSearch(no);
}
return resNode;
}
public HeroNode perOrderSearch1(int no){//为什么参数是 no 因为根据主方法 我们是根据英雄的编号查找
System.out.println("前序查找的次数");
//前序查找第一步 先打印根节点的信息
if (this.no==no){ //和普通的前序不同 满足了条件才能打印
return this ; //这里的打印就是return
}
HeroNode resNode=null;//最好要赋值初始值null
//实现左递归 只有左子树不为空的时候 才能递归
if (this.left!=null){
resNode=this.left.perOrderSearch1(no);//
//return resNode.perOrderSearch1(no); 这里错了 因为不能return 我这里的功能是递归 不是return
}
if (resNode!=null){//我觉得这个不仅仅是只有当左递归遍历到最后的时候 才会执行 而是每个结点都会执行
//resNode被赋值了 说明就找到了
return resNode;
}
//可以看到 左递归和右递归是对称的代码
if (this.right!=null){
resNode=this.right.perOrderSearch1(no);//只有找得到 resNode才会被赋值 否则还是null
//
}
return resNode;
}
//自己写的中序遍历
public HeroNode infixOrderSearch1(int no){
System.out.println("中序遍历的次数"); //注意这个不能写在这里
//先左递归
HeroNode resNode=null;
if (this.left!=null){
resNode=this.left.infixOrderSearch1(no);
}
if (resNode!=null){
return resNode;
}
System.out.println("中序遍历的次数"); //应该写在这里
if (this.no==no){
return this;
}
//右递归
if (this.right!=null){
resNode=this.right.infixOrderSearch1(no);
}
return resNode;
}
// 节点的中序遍历查找
public HeroNode infixOrderSearch(int no) {
// 1、判断当前左节点是否为空,若不为空,则继续左递归中序遍历查找
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.infixOrderSearch(no);
}
// 2、若不为空,则返回(既找到)
if (resNode != null) {
return resNode;
}
System.out.println("进入中序查找的次数统计");
// 3、和当前节点进行比较,若是则返回
if (this.no == no) {
return this;
}
// 4、若不是,则继续右递归中序遍历查找
if (this.right != null) {
resNode = this.right.infixOrderSearch(no);
}
return resNode;
}
//自己写的后续遍历
public HeroNode postOrderSearch1(int no){
HeroNode resNode=null;
if(this.left!=null){
resNode=this.left.postOrderSearch1(no);
}
if (resNode!=null){
return resNode;
}
if (this.right!=null){
resNode=this.right.postOrderSearch1(no);
}
if (resNode!=null){
return resNode;
}
if (this.no==no){
return this;
}
//这里少了一个语句
return resNode; //因为if里面的return 不能算作整个函数的return
}