吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1609|回复: 5
收起左侧

[Java 转载] 二叉树----遍历、查找、删除

[复制链接]
逸帅 发表于 2021-3-25 20:21

二叉树----遍历、查找、删除

1、为什么需要树?

  • 数组的查找效率高,但是插入效率低。
  • 链表的插入效率高,查找效率低。

2、二叉树

  • 二叉树的基本概念:每个节点最多只能由两个子节点的一种树叫做二叉树
  • 满二叉树:如果该二叉树的所有叶子节点都在最后一层,并且结点总数= 2n -1 , n为层数,则我们称为满二叉树。
  • 完全二叉树:如果该二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层的叶子节点在左边连续,倒数第二层的叶子节点在右边连续,我们称为完全二叉树

image-20210325172216128.png

3、二叉树的遍历

  1. 前序遍历

    先遍历父节点,再遍历左子节点,最后遍历右子节点

  2. 中序遍历

    先遍历左子节点,再遍历父节点,最后遍历右子节点

  3. 后序遍历

    先遍历左子节点,再遍历右子节点,最后遍历父节点

区别:看父节点什么时候遍历,在最前面就是前序,在中间就是中序,在最后就是后续

4、二叉树的遍历代码实现

class BinaryTree {
   /**
    * 根节点
    */
   private StuNode root;

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

   public void preTraverse() {
      if(root != null) {
         System.out.println("前序遍历");
         root.preTraverse();
         System.out.println();
      }else {
         System.out.println("二叉树为空!");
      }
   }

   public void midTraverse() {
      if(root != null) {
         System.out.println("中序遍历");
         root.midTraverse();
         System.out.println();
      }else {
         System.out.println("二叉树为空!");
      }  }

   public void lastTraverse() {
      if(root != null) {
         System.out.println("后序遍历");
         root.lastTraverse();
         System.out.println();
      }else {
         System.out.println("二叉树为空!");
      }  }
}

/**
 * 二叉树中的一个节点
 * 保存了学生信息和左右孩子信息
 */
@Data
class StuNode {
   int id;
   String name;
   StuNode left;
   StuNode right;

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

   @Override
   public String toString() {
      return "StuNode{" +
            "id=" + id +
            ", name='" + name + '\'' +
            '}';
   }

   /**
    * 前序遍历
    */
   public void preTraverse() {
      //父节点最开始就输出
      System.out.println(this);
      if(left != null) {
         left.preTraverse();
      }
      if(right != null) {
         right.preTraverse();
      }
   }

   /**
    * 中序遍历
    */
   public void midTraverse() {
      if(left != null) {
         left.midTraverse();
      }
      //父节点在中间输出
      System.out.println(this);
      if(right != null) {
         right.midTraverse();
      }
   }

   public void lastTraverse() {
      if(left != null) {
         left.lastTraverse();
      }
      if(right != null) {
         right.lastTraverse();
      }
      //父节点在最后输出
      System.out.println(this);
   }
}

5、二叉树的查找

与3是类似的,在遍历的过程中加一个判断,找到对应的元素直接返回即可!

6、二叉树的查找代码实现

class BinarySearchTree {
   private Student root;

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

   public void preSearch(int id) {
      System.out.println("前序查找");
      if(root == null) {
         System.out.println("树为空!");
         return;
      }
      Student result = root.preSearch(id);
      if(result == null) {
         System.out.println("未找到该元素");
         System.out.println();
         return;
      }
      System.out.println(result);
      System.out.println();
   }

   public void midSearch(int id) {
      System.out.println("中序查找");
      if(root == null) {
         System.out.println("树为空!");
         return;
      }
      Student result = root.midSearch(id);
      if(result == null) {
         System.out.println("未找到该元素");
         System.out.println();
         return;
      }
      System.out.println(result);
      System.out.println();
   }

   public void lastSearch(int id) {
      System.out.println("后序查找");
      if(root == null) {
         System.out.println("树为空!");
         return;
      }
      Student result = root.lastSearch(id);
      if(result == null) {
         System.out.println("未找到该元素");
         System.out.println();
         return;
      }
      System.out.println(result);
      System.out.println();
   }
}

@Data
class Student {
   int id;
   String name;
   Student left;
   Student right;

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

   @Override
   public String toString() {
      return "Student{" +
            "id=" + id +
            ", name='" + name + '\'' +
            '}';
   }

   /**
    * 前序查找
    * home.php?mod=space&uid=952169 id 要查找的学生id
    * home.php?mod=space&uid=155549 查找到的学生
    */
   public Student preSearch(int id) {
      //如果找到了,就返回
      if(this.id == id) {
         return this;
      }

      //在左子树中查找,如果找到了就返回
      Student student = null;
      if(left != null) {
         student = left.preSearch(id);
      }
      if(student != null) {
         return student;
      }

      //在右子树中查找,无论是否找到,都需要返回
      if(right != null) {
         student = right.preSearch(id);
      }
      return student;
   }

   /**
    * 中序查找
    * @param id 要查找的学生id
    * @return 查找到的学生
    */
   public Student midSearch(int id) {
      Student student = null;
      if(left != null) {
         student = left.midSearch(id);
      }
      if(student != null) {
         return student;
      }

      //找到了就返回
      if(this.id == id) {
         return this;
      }

      if(right != null) {
         student = right.midSearch(id);
      }
      return student;
   }

   /**
    * 后序查找
    * @param id 要查找的学生id
    * @return 查找到的学生
    */
   public Student lastSearch(int id) {
      Student student = null;
      if(left != null) {
         student = left.lastSearch(id);
      }
      if(student !=null) {
         return student;
      }

      if(right != null) {
         student = right.lastSearch(id);
      }

      if(this.id == id) {
         return this;
      }
      return student;
   }
}

7、二叉树节点的删除

  • 如果删除的节点是叶子节点,则删除该节点

  • 如果删除的节点是非叶子节点,则删除该子树.

7.1、删除节点的思路:

  1. 先考虑是否是个空树,即root节点是否为null
  2. 因为我们的二叉树是单向的,所以我们是判断当前结点的子结点是否需要删除结点,而不能去判断当前这个结点是不是需要删除结点(假如找到了当前节点,就无法找到当前节点的父节点,也就意味着无法删除当前节点了)
  3. 如果当前结点的左子结点不为空,并且左子结点就是要删除结点,就将 this.left = null; 并且就返回 (结束递归删除)
  4. 如果当前结点的右子结点不为空,并且右子结点就是要删除结点,就将 this.right= null ;并且就返回 (结束递归删除)
  5. 如果第2和第3步没有删除结点,那么我们就需要向左子树进行递归删除
  6. 如果 4步也没有删除结点,则应当向右子树进行递归删除

7.2、删除节点的代码实现

class BinaryDeleteTree {
   StudentNode root;

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

   /**
    * 删除节点
    * @param id 删除节点的id
    */
   public void deleteNode(int id) {
      System.out.println("删除节点");
      if(root.id == id) {
         root = null;
         System.out.println("根节点被删除");
         return;
      }
      //调用删除方法
      root.deleteNode(id);
   }
}

@Data
class StudentNode {
   int id;
   String name;
   StudentNode left;
   StudentNode right;

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

   @Override
   public String toString() {
      return "StudentNode{" +
            "id=" + id +
            ", name='" + name + '\'' +
            '}';
   }

   /**
    * 删除节点
    * @param id 删除节点的id
    */
   public void deleteNode(int id) {
      //如果左子树不为空且是要查找的节点,就删除
      if(left != null && left.id == id) {
         left = null;
         System.out.println("删除成功");
         return;
      }

      //如果右子树不为空且是要查找的节点,就删除
      if(right != null && right.id == id) {
         right = null;
         System.out.println("删除成功");
         return;
      }

      //左递归,继续查找
      if(left != null) {
         left.deleteNode(id);
      }

      //右递归,继续查找
      if(right != null) {
         right.deleteNode(id);
      }
   }
}

免费评分

参与人数 5吾爱币 +4 热心值 +5 收起 理由
RE1AX + 1 + 1 我很赞同!
Mandrake + 1 + 1 谢谢@Thanks!
LucretiaAgi + 1 + 1 我很赞同!
巡山的小旋风 + 1 + 1 我很赞同!
maltosio + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

红蓝黄 发表于 2021-3-25 20:23
以前学得很好,现在全忘了
yiwanyiwan 发表于 2021-3-25 20:33
LucretiaAgi 发表于 2021-3-25 21:59
谢谢大佬分享数据结构相关教程和代码,受益良多。
Mandrake 发表于 2021-3-25 22:18
学过不用,渐渐忘记
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-11 23:23

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表