当前位置: 首页 > news >正文

数据结构——二叉树(Binary Tree)

一、二叉树(Binary Tree)

(一)基本概念

        二叉树是每个节点最多有两个子节点的树结构,通常称为左子节点(left child)和右子节点(right child)。

(二)基本特性

  1. 节点结构:每个节点包含三个部分

    • 数据域(存储节点的值)

    • 左指针(指向左子节点)

    • 右指针(指向右子节点)

  2. 基本性质

    • 第i层最多有2^(i-1)个节点

    • 深度为k的二叉树最多有2^k - 1个节点

    • 对于任何非空二叉树,叶节点数等于度为2的节点数加1

(三)常见类型

  1. 满二叉树:每一层的节点数都达到最大值

  2. 完全二叉树:除最后一层外其他层都是满的,且最后一层节点都靠左排列

  3. 二叉搜索树(BST):左子树所有节点值小于根节点,右子树所有节点值大于根节点

  4. 平衡二叉树(AVL树):任何节点的左右子树高度差不超过1

  5. 红黑树:自平衡的二叉搜索树,保证了最坏情况下的操作时间复杂度

(四)遍历方式

1. 基本概念

        树的遍历是指按照某种顺序访问树中的所有节点,确保每个节点都被访问且仅被访问一次。根据访问顺序的不同。

2. 遍历类型

  1. 深度优先遍历(DFS)

    • 前序遍历:根→左→右

    • 中序遍历:左→根→右

    • 后序遍历:左→右→根

  2. 广度优先遍历(BFS)

                层次遍历:按从上到下、从左到右的顺序访问节点

3. 遍历方法详解        

前序遍历(Preorder Traversal)

        访问顺序:根节点 → 左子树 → 右子树

        算法步骤

  1. 访问根节点

  2. 前序遍历左子树

  3. 前序遍历右子树

        示例: 对于二叉树:

    A/ \B   C/ \
D   E

        前序遍历结果为:A → B → D → E → C

中序遍历(Inorder Traversal)

        访问顺序:左子树 → 根节点 → 右子树

        算法步骤

  1. 中序遍历左子树

  2. 访问根节点

  3. 中序遍历右子树

        示例: 使用前例中的二叉树: 中序遍历结果为:D → B → E → A → C

后序遍历(Postorder Traversal)

        访问顺序:左子树 → 右子树 → 根节点

        算法步骤

  1. 后序遍历左子树

  2. 后序遍历右子树

  3. 访问根节点

        示例: 使用前例中的二叉树: 后序遍历结果为:D → E → B → C → A

层次遍历(Level Order Traversal)

        按树的层次从上到下,从左到右访问节点

        实现方法: 通常使用队列辅助实现:

  1. 将根节点入队

  2. 当队列不为空时:

    • 出队一个节点并访问

    • 将其左右子节点(如果存在)依次入队

        示例: 使用前例中的二叉树: 层次遍历结果为:A → B → C → D → E

二、有序二叉树(Binary Search Tree)

(一)基本概念

        有序二叉树(Binary Search Tree,BST)是一种特殊的二叉树数据结构,它具有以下关键特性:

  1. 有序性:对于树中的每个节点:

    • 左子树中所有节点的值都小于该节点的值

    • 右子树中所有节点的值都大于该节点的值

    • 没有重复节点(可以有变体允许重复)

  2. 结构特性

    • 每个节点最多有两个子节点

    • 通常包含三个属性:值、左子节点指针和右子节点指针

(二)基本操作

1. 查找操作

        查找流程:

  1. 从根节点开始比较

  2. 如果查找值等于当前节点值,返回该节点

  3. 如果查找值小于当前节点值,递归查找左子树

  4. 如果查找值大于当前节点值,递归查找右子树

  5. 如果到达空节点,则查找失败

2. 插入操作

        插入流程:

  1. 如果树为空,创建新节点作为根节点

  2. 否则,从根节点开始比较

  3. 如果插入值小于当前节点值:

    • 如果左子节点为空,插入为左子节点

    • 否则递归处理左子树

  4. 如果插入值大于当前节点值:

    • 如果右子节点为空,插入为右子节点

    • 否则递归处理右子树

3. 删除操作

        删除有三种情况:

  1. 删除叶子节点:直接删除

  2. 删除有一个子节点的节点:用其子节点替换

  3. 删除有两个子节点的节点

    • 找到右子树的最小节点(或左子树的最大节点)

    • 用该节点值替换要删除的节点值

    • 递归删除该最小/最大节点

4. 遍历操作

三、实现示例(Java实现)

public class BinaryTree {public Node root;//	插入public void insert(int num) {Node node = new Node(num);if(root==null) {root=node;return;}Node index = root;while(true) {if(index.value>num) {if(index.left==null) {index.left=node;return;}index=index.left;}else {if(index.right==null) {index.right=node;return;}index=index.right;}}}//	遍历
//	先序遍历public void beforeOrder(Node node) {if(node==null) {return;}System.out.println(node.value);beforeOrder(node.left);beforeOrder(node.right);}//	中序遍历public void inOrder(Node node) {if(node==null) {return;}inOrder(node.left);System.out.println(node.value);inOrder(node.right);}//	后序遍历public void afterOrder(Node node) {if(node==null) {return;}afterOrder(node.left);afterOrder(node.right);System.out.println(node.value);}	//	广度优先遍历public void levelOrder() {Queue<Node> queue = new LinkedList<Node>();queue.add(root);while(!queue.isEmpty()) {Node index = queue.poll();System.out.println(index.value);if(index.left!=null) {queue.add(index.left);}if(index.right!=null) {queue.add(index.right);}}}//	查找public Node search(int num) {if(root==null) {return null;}Node index = root;while(index!=null) {if(index.value==num) {//相等,找到了return index;}else if(index.value<num) {index = index.right;}else {index = index.left;}}return null;}//    找父级节点public Node searchParent(int num) {if(root.value==num) {//根节点的值和目标值相等return null;}Node index = root;while(index!=null) {if((index.left!=null&&index.left.value==num)||(index.right!=null&&index.right.value==num)) {return index;}else if(index.value>num) {index=index.left;}else {index=index.right;}}return null;}//	删除public void delete(int num) {//找目标节点Node target = search(num);if(target==null) {System.out.println("没有这个节点");return;}//找目标节点的父节点Node parent = searchParent(num);//删除if(target.left==null&&target.right==null) {//删除叶子节点//如果没有父节点if(parent==null) {root=null;return;}//如果有父节点//判断目标节点是左孩子还是右孩子if(parent.left!=null&&parent.left.value==num) {//左孩子parent.left = null;}else {//右孩子parent.right=null;}}else if (target.left!=null&&target.right!=null) {//删除有两颗子树的节点//目标节点右子树的最小值ֵNode index = target.right;while (index.left!=null) {index=index.left;}//最小值ֵint min = index.value;//先删除delete(min);//替换target.value = min;}else {//删除只有一颗子树的节点//没有父节点if(parent==null) {//判断目标节点是左孩子还是右孩子if(target.left!=null) {//左子树root =  target.left;}else {//右子树root =  target.right;}return;}//有父节点//判断目标节点是左孩子还是右孩子if(parent.left!=null&&parent.left.value==num) {//左孩子//判断目标节点有左子树还是右子树if(target.left!=null) {//左子树parent.left = target.left;}else {//右子树parent.left = target.right;}}else {//右孩子//判断目标节点有左子树还是右子树if(target.left!=null) {//左子树parent.right = target.left;}else {//右子树parent.right = target.left;}}}}@Overridepublic String toString() {return "BinaryTree [root=" + root + "]";}
}
http://www.dtcms.com/a/342869.html

相关文章:

  • 自然语言处理NLP L4: 高级语言模型——四种泛化平滑方式
  • Spring全家桶之全局异常处理
  • Spring Boot生态中ORM对数据治理的支持有哪些?
  • Ubuntu22.04配置网络上网
  • linux-ubuntu里docker的容器portainer容器建立后如何打开?
  • Maven无法修改镜像,镜像在IDEA里不生效
  • 室外和室内 PoE 延长器有什么区别?
  • [CSP-J2020] 直播获奖
  • 集成学习:从原理到实战,一文掌握 Bagging、Boosting 与 Stacking
  • 集成学习:如何让多个 “弱模型” 变成 “强模型”?
  • demo 汽车之家(渲染-筛选-排序-模块抽离数据)
  • Linux之Ansible自动化运维(二)
  • Linux内核源码详解--缺页异常(Page Fault)处理的核心函数handle_pte_fault
  • Maven(三)
  • Class A 包含字段 x Class B 也包含字段 x,如果判断List<A> lista 和 List<B> listb 有相同的 x?
  • 基于websocket聊天室的基本点
  • SQL中的游标
  • html ajax前端页面
  • 51单片机-驱动直流电机模块教程
  • 单片机\物联网\51单片机\嵌入式开发\软硬件结合的基于STM32的电梯管理系统的设计/基于STM32的电梯运行系统的设计
  • 【华为OD-C卷-020 -关联端口组合并 100分(python、java、c++、js、c)】
  • 解决 uniapp 修改index.html文件不生效的问题
  • PCB文件怎么快速判断是通孔还是盲孔呢?
  • Git 2.15.0 64位安装步骤Windows详细教程从下载到验证(附安装包下载)
  • 14、外部中断
  • 【科普向-第三篇】汽车电子MCU操作系统详解:CP AUTOSAR与FreeRTOS
  • 1688电商商品大数据采集之路 技术篇
  • 嵌入式接口通识知识之PWM接口
  • 机器学习聚类与集成算法全解析:从 K-Means 到随机森林的实战指南
  • 从系统漏洞归零到候诊缩短20%:一个信创样本的效能革命