【Java数据结构与算法】第十章 哈希表和二叉树

第十章 哈希表和二叉树

一、哈希表

1.介绍

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表

给定表 M,存在函数 f (key),对任意给定的关键值 key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表 M 为哈希(Hash)表,函数 f (key) 为哈希(Hash) 函数

基本概念

  • 若关键字为 k,则其值存放在 f(k) 的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系 f 为散列函数,按这个思想建立的表为散列表
  • 对不同的关键字可能得到同一散列地址,即 k1 ≠ k2,而 f(k1) = f(k2),这种现象称为冲突(Collision)。具有相同函数值的关键字对该散列函数来说称作同义词。综上所述,根据散列函数 f(k) 和处理冲突的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的 ”像“ 作为记录在表中的存储位置,这种表便称为散列表,这一映射过程称为散列造表或散列,所得的存储位置称散列地址
  • 若对于关键字集合中的任一个关键字,经散列函数映像到地址集合中任何一个地址的概率是相等的,则称此类散列函数为均匀散列函数(Uniform Hash function),这就是使关键字经过散列函数得到一个 ”随机的地址“,从而减少冲突

哈希表可以通过数组 + 链表实现,也可以通过数组 + 二叉树实现

提出问题:
有一个公司,当有新员工来报到时,要求将该员工的信息加入(id,性别,年龄,住址…),当输入该员工的 id 时,要求查找到该员工的所有信息,要求使用哈希表

数据结构设计:

class HashTab{
	EmplinkedList[];	//链表
	empLinkedListArr;	//链表数组
	add();
	list();
	find();
	散列函数();	//决定 id 对应到哪个链表
}

class EmpLinkedList{
	Emp head = null;	//头指针,指向当前链表的第一个雇员
	add();
	list();
	find();
}

class Emp{
	id;
	name;
	address;
}

2.代码实现

package com.sisyphus.hashtab;

import java.util.Scanner;

/**
 * @Description: 哈希表$
 * @Param: $
 * @return: $
 * @Author: Sisyphus
 * @Date: 7/22$
 */
public class HashTabDemo {
    public static void main(String[] args) {
        //创建哈希表
        HashTab hashTab = new HashTab(7);

        //写一个简单的菜单
        String key = "";
        Scanner scanner = new Scanner(System.in);
        while(true){
            System.out.println("add:添加雇员");
            System.out.println("list:显示雇员");
            System.out.println("find:查找古语店");
            System.out.println("exit:退出系统");

            key = scanner.next();
            switch (key){
                case "add":
                    System.out.println("输入id");
                    int id = scanner.nextInt();
                    System.out.println("输入名字");
                    String name = scanner.next();
                    //创建雇员
                    Emp emp = new Emp(id,name);
                    hashTab.add(emp);
                    break;
                case "list":
                    hashTab.list();
                    break;
                case "find":
                    System.out.println("输入id");
                    id = scanner.nextInt();
                    hashTab.findEmpById(id);
                    break;
                case "exit":
                    scanner.close();
                    System.exit(0);
                default:
                    break;
            }
        }
    }
}

//创建 HashTab 管理多条链表
class HashTab{
    private EmpLinkedList[] empLinkedListArray;
    private  int size;//表示有多少条链表

    //构造器
    public HashTab(int size){
        this.size = size;
        //初始化 empLinkedListArray
        empLinkedListArray = new EmpLinkedList[size];
        //分别初始化每个链表
        for (int i = 0; i < size; i++) {
            empLinkedListArray[i] = new EmpLinkedList();
        }
    }

    //添加雇员
    public void add(Emp emp){
        //根据员工的 id,得到该员工应当添加到哪条链表
        int empLinkedListNo = hashFun(emp.id);
        //将 emp 添加到对应的链表中
        empLinkedListArray[empLinkedListNo].add(emp);
    }
    //遍历所有的链表,遍历 hashtab
    public void list(){
        for (int i = 0; i < size; i++) {
            empLinkedListArray[i].list(i);
        }
    }

    //根据输入的 id 查找雇员
    public void findEmpById(int id){
        //使用散列函数确定要到哪条链表查找
        int empLinkedListNo = hashFun(id);
        Emp emp = empLinkedListArray[empLinkedListNo].findEmpById(id);
        if (emp != null){
            System.out.printf("在第%d条链表中找到雇员 id = %d\n",(empLinkedListNo + 1),id);
        }else{
            System.out.println("在哈希表中,没有找到该雇员~");
        }
    }

    //编写散列函数,使用一个简单的取模法
    public int hashFun(int id){
        return id % size;
    }

}

//表示一个雇员
class Emp{
    public int id;
    public String name;
    public Emp next;    //next 默认为空

    public Emp(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
}

//创建 EmpLinkedList,表示链表
class EmpLinkedList{
    //头指针,执行第一个 Emp,因此我们这个链表的 head 是直接指向第一个 Emp
    private Emp head;   //默认为 null

    //添加雇员到链表
    //说明
    //1.假定,当添加雇员时,id 时自增长的,即 id 的分配总是从小到大
    // 因此我们将该雇员直接加入到本链表的最后即可
    public void add(Emp emp){
        //如果时添加第一个雇员
        if(head == null){
            head = emp;
            return;
        }
        //如果不是第一个雇员,则使用一个辅助的指针,帮助定位到最后
        Emp curEmp = head;
        while(true){
            if (curEmp.next == null){   //说明到达链表最后
                break;
            }
            curEmp = curEmp.next;   //后移
        }
        //退出时直接将 emp 加入链表
        curEmp.next = emp;
    }
    //遍历链表的雇员信息
    public void list(int no){
        if (head == null){  //说明链表为空
            System.out.println("第" + (no + 1) + "链表为空");
            return;
        }
        System.out.print("第" + (no + 1) + "条链表信息为为");
        Emp curEmp = head;  //辅助指针
        while(true){
            System.out.printf("=> id=%d name=%s\t",curEmp.id,curEmp.name);

            if (curEmp.next == null){//说明 curEmp 已经是最后结点
                break;
            }
            curEmp = curEmp.next;//后移,遍历
        }
        System.out.println();
        }
    //根据 id 查找雇员
    //如果查找到,就返回 Emp,如果没有找到,就返回 null
    public Emp findEmpById(int id){
        //判断链表是否为空
        if (head == null){
            System.out.println("链表为空");
            return null;
        }
        //辅助指针
        Emp curEmp = head;
        while(true){
            if (curEmp.id == id){//找到
                break;  //这时 curEmp 就指向要查找的雇员
            }

            //退出
            if (curEmp.next == null){   //说明遍历当前链表没有找到该雇员
                curEmp = null;
                break;
            }
            curEmp = curEmp.next;   //后移
        }
        return curEmp;
    }
}

在这里插入图片描述

二、二叉树

1.介绍

在这里插入图片描述

二叉树(binary tree)是指树中节点的度不大于 2 的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树

相关术语:

  1. 结点:包含一个数据元素及若干指向子树分支的信息
  2. 结点的度:一个结点拥有子树的数目称为结点的度
  3. 叶子结点:也称为终端结点,没有子树的结点或者度为零的结点
  4. 分支结点:也称为非终端结点,度不为零的结点称为非终端结点
  5. 树的度:树中所有结点的度的最大值
  6. 结点的层次:从根结点开始,假设根结点为第 1 层,根结点的子结点为第 2 层,依此类推,如果某一个结点位于第 L 层,则其子结点位于 L + 1 层
  7. 树的深度:也称为树的高度,树中所有结点的层次最大值称为树的深度
  8. 有序树:如果树中各棵子树的次序是有先后次序,则称该树为有序树
  9. 无序树:如果树中各棵子树的次序没有先后次序,则称该树为无序树
    10.森林:由 m (m ≥ 0) 棵互不相交的树构成一片森林。如果把一棵非空的树的根结点删除,则该树就变成了一片森林,森林中的树由原来根结点的各棵子树构成

特殊类型:

  • 满二叉树:指的是深度为 k 且含有 2^k - 1 个结点的二叉树
  • 完全二叉树:设二叉树的深度为 h,除第 h 层外,其他各层的结点数都达到最大个数,且第 h 层所有的结点都连续集中在最左边。也就是说,树中所含的 n 个结点和满二叉树中编号为 1 至 n 的结点一一对应
    • 第 n 个元素的左子结点为 2n
    • 第 n 个元素的右子结点为 2n + 1
    • 第 n 个元素的父结点为 (n - 1)/ 2

性质:

  1. 二叉树的第 i 层上至多有 2^(i - 1) 个点(i ≥ 1)
  2. 深度为 h 的二叉树中至多含有 2^h - 1 个结点
  3. 若在任意一棵二叉树中,有 n0 个叶子结点,有 n2 个度为 2 的结点,则必有 n0 = n2 + 1
  4. 具有 n 个 结点的完全二叉树深度为 log2(x + 1) ,其中 x 表示不大于 n 的最大整数
  5. 若对一棵有 n 个结点的完全二叉树进行顺序编号(1 ≤ i ≤ n),那么,对于编号为 i (i ≥ 1)的结点:
    当 i = 1 时,该结点为根,它无双亲结点
    当 i > 1 时,该结点的双亲结点的编号为 i / 2
    若 2i < n,则有编号为 2i 的左结点,否则没有左结点
    若 2i + 1 ≤ n,则有编号为 2i + 1 的右节点,否则没有右节点

2.遍历二叉树

前序遍历二叉树
在这里插入图片描述

思路:
访问到一个结点后就打印该结点,并继续遍历其左右子树

遍历顺序:
GDAFEMHZ

代码实现:

//前序遍历
public void preOrder(){
    //打印父结点
    System.out.println(this);
    //递归向左子树前序遍历
    if (this.left != null){
        this.left.preOrder();
    }
    //递归向右子树前序遍历
    if (this.right != null){
        this.right.preOrder();
    }
}

中序遍历二叉树
在这里插入图片描述

思路:
访问到一个结点后将其暂存,遍历完左子树后,再打印该结点的值,然后遍历右子树

遍历顺序:
ADEFGHMZ

代码实现:

//中序遍历
public void infixOrder(){
    //递归向左子树中序遍历
    if (this.left != null){
        this.left.infixOrder();
    }
    //打印父结点
    System.out.println(this);
    //递归向右子树中序遍历
    if (this.right != null){
        this.right.infixOrder();
    }
}

后续遍历二叉树
在这里插入图片描述

思路:
访问到一个结点后将其暂存,遍历完左右子树后,再打印该结点的值

遍历顺序:
AEFDHZMG

代码实现:

//后序遍历
public  void postOrder(){
    //递归向左子树后序遍历
    if (this.left != null){
        this.left.postOrder();
    }
    //递归向右子树后序遍历
    if (this.right != null){
        this.right.postOrder();
    }
    //打印父结点
    System.out.println(this);
}

层次遍历二叉树
在这里插入图片描述

思路:
建立一个循环队列,先将二叉树根结点入队列,然后出队列,访问根结点,如果它有左子树,则将左子树的根结点入队:如果它有右子树,则将右子树的根结点入队。然后出队列,对出队结点访问,如此反复,直到队列为空为止

遍历顺序:
ADMAFHZ

代码实现:

//层次遍历
    public void levelOrder(){
        ArrayDeque<HeroNode> queue = new ArrayDeque<>(20);
        //首先将根结点加入队列中
        queue.add(this);
        //遍历二叉树
        while(!queue.isEmpty()){
            HeroNode tempNode = queue.poll();
            System.out.println(tempNode);

            if (tempNode.left != null){
                queue.add(tempNode.left);
            }
            if (tempNode.right != null){
                queue.add(tempNode.right);
            }
        }
    }

3.查找二叉树

前序查找二叉树
在这里插入图片描述

思路:

  1. 首先拿根结点进行比较,如果相等,直接返回,否则左递归前序查找
  2. 如果左递归找到,直接返回,否则右递归前序查找
  3. 如果右递归找到返回,否则返回空

查到 H 结点
比较次数:
7

代码实现:

//前序遍历
    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;
    }

中序查找二叉树
在这里插入图片描述

思路:

  1. 首先左递归查找,如果找到,直接返回,否则和根结点比较
  2. 如果比较相等,直接返回,否则右递归中序查找
  3. 如果右递归找到则返回,否则返回空

查找 H 结点
比较次数:
6

代码实现:

//中序遍历
    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;
    }

后序查找二叉树
在这里插入图片描述

思路:

  1. 首先左递归查找,如果找到,直接返回,否则右递归中序查找
  2. 如果右递归找到,直接返回,否则和根结点比较
  3. 如果比较不相等则返回空

查找 H 结点
比较次数:
5

代码实现:

//后序遍历
    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;
    }

4.二叉树删除节点

思路:

  • 如果删除的结点就是 root结点,则等价将二叉树置空
  • 如果删除的结点是非叶子结点,则删除该子树
  • 如果删除的结点是叶子结点,则删除该结点
  • 因为我们的二叉树是单向的,所以只能判断当前结点的子结点是不是需要删除结点
  1. 如果当前结点的左子结点不为空,并且左子结点就是要删除的结点,执行 this.left = null,并 return
  2. 如果当前结点的右子结点不为空,并且左子结点就是要删除的结点,执行 this.right = null,并 return
  3. 如果第 1 步和第 2 步没有 return,那么我们就需要向左子树进行递归删除
  4. 如果第 3 步仍没有 return,则向右子树进行递归删除

5.二叉树综合实例

代码:

package com.sisyphus.tree;

import java.util.ArrayDeque;

/**
 * @Description: 二叉树$
 * @Param: $
 * @return: $
 * @Author: Sisyphus
 * @Date: 7/23$
 */
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, "关胜");

        //说明,我们先手动创建该二叉树,后面我们学习递归的方式创建二叉树
        root.setLeft(node2);
        root.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);
        binaryTree.setRoot(root);

        System.out.println("前序遍历"); //12354
        binaryTree.preOrder();

        System.out.println("中序遍历"); //21534
        binaryTree.infixOrder();

        System.out.println("后序遍历"); //25431
        binaryTree.postOrder();

        //前序遍历
        System.out.println("前序遍历");
        HeroNode resNode = binaryTree.preOrderSearch(5);
        if (resNode != null){
            System.out.printf("找到了,信息为 no=%d name=%s",resNode.getNo(),resNode.getName());
            System.out.println();
        }else{
            System.out.printf("没有找到 no=%d 的英雄",5);
            System.out.println();
        }
        //中序遍历
        System.out.println("中序遍历");
        resNode = binaryTree.infixOrderSearch(5);
        if (resNode != null){
            System.out.printf("找到了,信息为 no=%d name=%s",resNode.getNo(),resNode.getName());
            System.out.println();
        }else{
            System.out.printf("没有找到 no=%d 的英雄",5);
            System.out.println();
        }
        //后序遍历
        System.out.println("后序遍历");
        resNode = binaryTree.postOrderSearch(5);
        if (resNode != null){
            System.out.printf("找到了,信息为 no=%d name=%s",resNode.getNo(),resNode.getName());
            System.out.println();
        }else{
            System.out.printf("没有找到 no=%d 的英雄",5);
            System.out.println();
        }

        System.out.println("===================================================");

        //测试删除结点
        System.out.println("删除前,前序遍历");
        binaryTree.preOrder();
        binaryTree.delNode(5);
        System.out.println("删除后,前序遍历");
        binaryTree.preOrder();

        System.out.println("======================================================");
        System.out.println("层次遍历");
        binaryTree.levelOrder();

    }
}

//定义 BinaryTree 二叉树
class BinaryTree{
    private HeroNode root;

    public void setRoot(HeroNode root){
        this.root = root;
    }

    //删除结点
    public void delNode(int no){
        if (root != null){
            //如果只有一个 root 结点,这里立即判断 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 void levelOrder(){
        if (this.root != null){
            this.root.levelOrder();
        }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;
        }
    }
}

//先创建 HeroNode 结点
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){
        if (this.left != null && this.left.no == no){
            this.left = null;
            return;
        }
        if (this.right != null && this.right.no == no){
            this.right = null;
            return;
        }
        if (this.left != null){
            this.left.delNode(no);
        }
        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);
    }
    //层次遍历
    public void levelOrder(){
        ArrayDeque<HeroNode> queue = new ArrayDeque<>(20);
        //首先将根结点加入队列中
        queue.add(this);
        //遍历二叉树
        while(!queue.isEmpty()){
            HeroNode tempNode = queue.poll();
            System.out.println(tempNode);

            if (tempNode.left != null){
                queue.add(tempNode.left);
            }
            if (tempNode.right != null){
                queue.add(tempNode.right);
            }
        }
    }

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    //查找

    //前序遍历
    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 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;
    }
    //后序遍历
    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;
    }
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

313YPHU3

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值