手劈二叉树

news2024/11/23 18:36:28

二叉树

概念

二叉树是一种常见的树状数据结构,每个节点最多有两个子节点,称为左子节点
和右子节点。它可以为空树(没有任何节点),或者由根节点及其子节点组成。

在这里插入图片描述

特点

具有层级结构,其中顶层的节点被称为根节点(root)。根节点没有父节点,而其
他节点都有且只有一个父节点。叶子节点是指没有子节点的节点,它们位于树的
最底层。

定义要点

节点(Node):二叉树的基本单位。每个节点包含三个主要部分:

数据/值域:节点中存储的具体数据,可以是任何类型,例如整数、字符、对
	象等。

左子节点:指向当前节点的左侧子节点的指针。如果没有左子节点,指针的值
	为None或null。

右子节点:指向当前节点的右侧子节点的指针。如果没有右子节点,指针的值
	为None或null。

根节点(Root Node):二叉树的顶层节点,没有父节点。根节点是整个二叉树
	的起点。

子节点(Child Node):每个节点可以有零个、一个或两个子节点。左子节点和
	右子节点是相对于父节点而言的。

叶子节点(Leaf Node):没有子节点的节点被称为叶子节点。叶子节点位于二叉
	树的最底层。

父节点(Parent Node):一个节点的直接上层节点被称为其父节点。

兄弟节点(Sibling Node):具有相同父节点的节点之间称为兄弟节点。

节点之间的连接(Edges):边是连接节点的线条或指针,它表示一个节点与其子
	节点之间的关系。

空树(Empty Tree):没有任何节点的二叉树被称为空树。在空树中,根节点为
	 None 或 null。

二叉树(Binary Tree):是一种有序树结构,其中每个节点最多有两个子节点,
	即左子节点和右子节点。左子节点和右子节点的顺序是固定的。

二叉树的形态:二叉树可以具有不同的形态和结构,它可以是平衡的或非平衡
	的,可以是满二叉树、完全二叉树或非完全二叉树等。

二叉树的高度(Height):二叉树的高度是指从根节点到最深叶子节点的层数。
	空树的高度为0,只有根节点的树的高度为1。

在这里插入图片描述

性质

最大节点数量:
	在二叉树的第n层,最多有2^(n-1)个节点。
	在高度为h的二叉树中,最多有2^h - 1个节点。
最小高度:
	对于含有n个节点的二叉树,它的最小高度为 log2(n+1)。
	如果二叉树是平衡树,那么它的最小高度为 floor(log2(n+1))。
树的高度:
	树的高度是指从根节点到最深叶子节点的路径上的边数。
		对于n个节点的二叉树,它的高度最大为n,最小为log2(n+1)。
		子树的高度:
	二叉树的任意子树的高度不会超过整个二叉树的高度。叶子节点数和度为2
		的节点数:

在二叉树中,度为2的节点数等于叶子节点数加1。

在这里插入图片描述

完全二叉树的性质:

完全二叉树是一种特殊的二叉树,除了最后一层外,其他层的节点都必须是满的。
在完全二叉树中,叶子节点从左到右依次排列,不会出现在左侧缺少叶子节点的
	情况。
完全二叉树可以使用数组来表示,节点按照层序遍历的顺序依次存放在数组中。

二叉搜索树的性质:

二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树,满足以下性质:
	左子树上的所有节点的值都小于根节点的值。
	右子树上的所有节点的值都大于根节点的值。
	左右子树也分别是二叉搜索树。
	在二叉搜索树中,通过比较节点的值可以快速地搜索、插入和删除节点。

存储结构

二叉树可以使用不同的存储结构来表示其节点和连接关系。常见的二叉树存储结
构包括链式存储和数组存储。下面对这两种存储结构进行详细讲解:

链式存储(Linked Representation):

链式存储使用节点来表示二叉树的各个部分,每个节点包含数据和指向左右子节
点的指针。链式存储可以通过类、结构体或节点对象实现。其中,每个节点由数
据域、左子节点指针和右子节点指针组成。

在这里插入图片描述

数组存储(Array Representation):

数组存储使用数组来表示二叉树的节点和连接关系。数组的索引可以代表节点在
二叉树中的位置,节点的值存储在数组对应位置上。

在这里插入图片描述

二者对比

链表存储结构的优点:

灵活性高:链表存储结构可以动态地插入和删除节点,不需要提前确定存储空间
	的大小。
支持任意形态的二叉树:链表存储结构可以直接表示任意形态的二叉树,包括不
	平衡和不完全的二叉树。
内存利用效率高:链表存储结构只需要为每个节点分配内存,不会浪费空间。

链表存储结构的缺点:

额外的指针开销:链表存储结构需要为每个节点维护两个指针(左子节点和右子
	节点),增加了额外的指针开销。
空间开销较大:相比数组存储结构,链表存储结构会占用更多的存储空间来存储
	指针信息。

数组存储结构的优点:

内存连续、访问高效:数组存储结构的节点在内存中是连续存储的,可以通过索
	引快速访问节点,访问效率较高。
空间利用效率高:对于满二叉树或完全二叉树这种特殊形态的二叉树,数组存储
	结构可以节省存储空间。

数组存储结构的缺点:

大小固定:数组存储结构需要提前确定二叉树的大小,当二叉树的节点数超过数
	组大小时,需要重新分配内存,导致性能下降。
插入和删除困难:对于数组存储结构,插入和删除节点的操作相对复杂且耗时,
	需要进行元素的移动和调整。

总结

综上所述,链表存储结构适用于频繁的修改操作和不规则形态的二叉树,它具有
灵活性和动态性的优势。而数组存储结构适用于满二叉树或完全二叉树这种特殊
形态的二叉树,它具有内存连续和访问高效的优势。

实际应用

搜索和排序算法:
二叉搜索树(Binary Search Tree,BST)是一种常用的数据结构,基于二叉树
实现。它具有快速的搜索、插入和删除操作,广泛用于搜索和排序算法,如二叉
搜索、二叉查找、二叉排序等。BST还可以根据中序遍历得到有序的数据序列。

文件系统的组织:
文件系统常常被组织成一棵树,其中每个节点代表一个目录或文件。使用二叉树
的方式可以方便地进行文件的搜索和管理操作,例如快速查找、遍历和删除文
件等。

表达式表示与求值:
二叉树可以用于表示数学表达式,其中每个节点表示操作符或操作数。通过遍历
二叉树,可以对表达式进行求值或转换。例如,通过后序遍历可以实现表达式求
值,通过中序遍历可以进行中缀表达式转换为后缀表达式。

解析和编译器设计:
编译器和解析器常常使用二叉树来解析源代码,并将其转换为语法树或抽象语法
树(Abstract Syntax Tree,AST)。语法树可以方便地对源代码进行分析、优
化和生成中间代码等。

网络和路由算法:
二叉树在网络和路由算法中有应用。例如,用于安全路由的Patricia树或前缀
树(Prefix Tree)是一种特殊的二叉树,可以高效地存储和查询路由信息。

Huffman编码:
Huffman编码是一种无损数据压缩算法,通过构建二叉树并对每个字符进行编码,
实现有效地压缩。二叉树中的叶子节点表示不同的字符,路径和编码表示字符的
编码。

数据库索引结构:
数据库中的索引结构常常使用二叉树的变种来实现,例如平衡二叉树、B	树和
B+树等。这些树结构可以加速数据库的查询和检索操作。

图形学和游戏开发:
在图形学和游戏开发中,二叉树可以用于场景图的构建和管理。场景图是一种用
于表示物体之间层次关系的树结构,便于进行碰撞检测、渲染优化和对象的空间
关系操作。

除此以外	
二叉树还可以在许多其他领域中使用,如人工智能中的决策树和神经网络,
网络协议等方面

代码示例

class Node {
    int key;
    Node left, right;

    public Node(int item) {
        key = item;
        left = right = null;
    }
}

public class BinaryTree {
    Node root;

    // 创建二叉树
    public BinaryTree(int key) {
        root = new Node(key);
    }

    public BinaryTree() {
        root = null;
    }

    // 插入节点
    public void insert(int key) {
        root = insertNode(root, key);
    }

    private Node insertNode(Node root, int key) {
        if (root == null) {
            root = new Node(key);
            return root;
        }

        if (key < root.key)
            root.left = insertNode(root.left, key);
        else if (key > root.key)
            root.right = insertNode(root.right, key);

        return root;
    }

    // 删除节点
    public void delete(int key) {
        root = deleteNode(root, key);
    }

    private Node deleteNode(Node root, int key) {
        if (root == null)
            return root;

        if (key < root.key)
            root.left = deleteNode(root.left, key);
        else if (key > root.key)
            root.right = deleteNode(root.right, key);
        else {
            if (root.left == null)
                return root.right;
            else if (root.right == null)
                return root.left;

            root.key = getMinValue(root.right);
            root.right = deleteNode(root.right, root.key);
        }

        return root;
    }

    private int getMinValue(Node root) {
        int minVal = root.key;
        while (root.left != null) {
            minVal = root.left.key;
            root = root.left;
        }
        return minVal;
    }

    // 搜索节点
    public Node search(Node root, int key) {
        if (root == null || root.key == key)
            return root;

        if (key < root.key)
            return search(root.left, key);

        return search(root.right, key);
    }

    // 前序遍历
    public void preorderTraversal(Node node) {
        if (node != null) {
            System.out.print(node.key + " ");
            preorderTraversal(node.left);
            preorderTraversal(node.right);
        }
    }

    // 中序遍历
    public void inorderTraversal(Node node) {
        if (node != null) {
            inorderTraversal(node.left);
            System.out.print(node.key + " ");
            inorderTraversal(node.right);
        }
    }

    // 后序遍历
    public void postorderTraversal(Node node) {
        if (node != null) {
            postorderTraversal(node.left);
            postorderTraversal(node.right);
            System.out.print(node.key + " ");
        }
    }

    public static void main(String[] args) {
        BinaryTree tree = new BinaryTree();

        // 插入节点
        tree.insert(50);
        tree.insert(30);
        tree.insert(20);
        tree.insert(40);
        tree.insert(70);
        tree.insert(60);
        tree.insert(80);

        // 删除节点
        tree.delete(20);

        // 搜索节点
        Node searchNode = tree.search(tree.root, 40);
        if (searchNode != null)
            System.out.println("节点 40 找到了");
        else
            System.out.println("节点 40 未找到");

        // 遍历二叉树
        System.out.println("前序遍历:");
        tree.preorderTraversal(tree.root);
        System.out.println("\n中序遍历:");
        tree.inorderTraversal(tree.root);
        System.out.println("\n后序遍历:");
        tree.postorderTraversal(tree.root);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/777577.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

请求头/响应头、POST的使用方法、常用协议状态码

POST请求方法&#xff1a;添加资源 常用的几种数据格式&#xff1a; 1、XML的格式 2、表单数据格式 3、JSON数据格式 请求地址 请求方法 请求头 请求参数 COOKI E&#xff1a; 1、反爬虫 2、身份认证 Referer:请求是从哪个页面发送过来的 User-Agent&#xff1a;通…

机器学习---经验误差与过拟合、方差与偏差、性能度量、比较检验

1. 经验误差与过拟合 第三张图建立的模型&#xff0c;在训练集中通过x可以很好的预测y&#xff0c;然而我们不能预期该模型能够很好的预 测集外的数据&#xff0c;换句话说&#xff0c;这个模型没有很好的泛化能力。 第一张图建立了一个线性模型&#xff0c;但是该模型并没有…

PHP中常用数组排序算法

一&#xff1a;冒泡排序 1&#xff1a;算法步骤 比较相邻项的值&#xff0c;如果前者比后者大&#xff0c;交换顺序。 进行一轮比较后&#xff0c;最后一个值为最大的值。 进行下一轮比较&#xff0c;比上次少比较一项。 以此类推&#xff0c;比较剩下最后一项的时候&#…

【Hive】group by 分组聚合后使用窗口函数

文章目录 1. group by 分组聚合后使用排序窗口函数1.1 两种思路 与 简单例子1.2 新思路的解释 2. group by 分组聚合后使用聚合窗口函数3. group by 分组聚合后使用分析窗口函数 1. group by 分组聚合后使用排序窗口函数 1.1 两种思路 与 简单例子 group by 之后&#xff0c;…

AI时代带来的图片造假危机,该如何解决

一、前言 当今&#xff0c;图片造假问题非常泛滥&#xff0c;已经成为现代社会中一个严峻的问题。随着AI技术不断的发展&#xff0c;人们可以轻松地通过图像编辑和AI智能生成来篡改和伪造图片&#xff0c;使其看起来真实而难以辨别&#xff0c;之前就看到过一对硕士夫妻为了骗…

【Linux】进程信号 -- 信号保存与递达 | 信号捕捉 | 僵尸进程的信号处理方法

阻塞信号信号相关概念内核中的表示sigset_t信号集操作函数sigprocmasksigpending 小实验 - 观察pending表 信号的捕捉流程sigaction1.小实验&#xff1a;如果进程在处理2号信号&#xff0c;那我们继续发送2号信号会怎么样&#xff1f;2.如何正在处理这个信号&#xff0c;同时屏…

js - 关于防抖和节流函数的使用和细节

文章目录 一、什么是防抖二、应用场景三、实现原理1&#xff0c;第一个问题&#xff1a;为什么使用了闭包&#xff08;也就是说timer为什么定义到了外面&#xff09;2&#xff0c;第二个问题&#xff1a;防抖函数中this的指向问题&#xff1a; 四、节流函数 一、什么是防抖 事…

【【51单片机的I2C总线】】

51单片机的I2C总线 学会总线&#xff0c;掌控芯片。了解串口&#xff0c;真理全有。 I&#xff12;C时序 &#xff11;.起始条件&#xff1a;  SCL在高电平期间&#xff0c;SDA从高电平切换到低电平 终止条件&#xff1a; SCL在高电平期间&#xff0c;SDA从低电平切换为高电…

【go语言学习笔记】01 Go语言快速入门

文章目录 一、基础入门1. 示例程序2. 安装与环境变量设置3. 项目构建和编译发布3.1 go build和go install对比3.2 跨平台编译 二、数据类型1. 基础类型1.1 整型1.2 浮点数1.3 布尔型1.4 字符串1.5 零值 2. 变量2.1 变量声明2.1.1 指定变量类型2.1.2 根据值自行判定变量类型2.1.…

深入学习 Redis - 深挖经典数据类型之 list

目录 前言 一、list 类型 1.1、操作命令 lpush / rpush&#xff08;插入元素&#xff09; lrange&#xff08;查看范围元素&#xff09; lpushx / rpushx &#xff08;有约束的插入&#xff09; lpop / rpop&#xff08;头删尾删&#xff09; lindex&#xff08;获取下…

2023年第三届能源、电力与电气工程国际会议 (CoEEPE 2023)

会议简介 Brief Introduction 2023年第三届能源、电力与电气工程国际会议(CoEEPE 2023) 会议时间&#xff1a;2023年11月22日-24日 召开地点&#xff1a;澳大利亚墨尔本 大会官网&#xff1a;www.coeepe.org 2023年第三届能源、电力与电气工程国际会议(CoEEPE 2023)由安徽大学、…

使用GGML和LangChain在CPU上运行量化的llama2

Meta AI 在本周二发布了最新一代开源大模型 Llama 2。对比于今年 2 月发布的 Llama 1&#xff0c;训练所用的 token 翻了一倍&#xff0c;已经达到了 2 万亿&#xff0c;对于使用大模型最重要的上下文长度限制&#xff0c;Llama 2 也翻了一倍。 在本文&#xff0c;我们将紧跟趋…

JavaScript基础语法及小案例

目录 JavaScript基础语法1. 变量声明和赋值2. 数据类型1) 基本数据类型2) 复合数据类型(引用类型)3) 特殊数据类型 3. 运算符1) 算术运算符2) 赋值运算符3) 比较运算符4) 逻辑运算符5) 三元运算符 4. 控制流程1) 条件语句2) 循环语句 5. 函数1) 函数的基本使用① 什么是函数② …

DXFReader.NET 2023 Crack

DXFReader.NET 是一个 .NET 组件&#xff0c;允许直接从 AutoCAD 图形文件格式 DXF&#xff08;也称为图形交换格式&#xff09;查看、操作和打印。 DXFReader.NET 之 DXF 是 Drawing eXchange Format 的首字母缩写。DXF 是图形文件内容的复制&#xff0c;支持将文件从一个 CA…

机器学习深度学习——预备知识(上)

深大的夏令营已经结束&#xff0c;筛选入营的保研er就筛选了1/3&#xff0c;280多的入营总人数里面双非只有30左右。 最终虽然凭借机试拿到offer了&#xff0c;但是我感受到了自己的明显短板&#xff0c;比如夏令营的舍友就都有一篇核心论文&#xff0c;甚至还有SCI一区一作的。…

Mac应用程序因“来自身份不明的开发者”无法打开如何解决

相信不少mac电脑用户在安装应用程序时经常会遇到“xxx.app已损坏&#xff0c;打不开。这是mac系统的新的安全机制&#xff0c;安装 App 时提示&#xff1a; 常见的几种报错提示 xxx 已损坏&#xff0c;无法打开。您应该将它移到废纸篓打不开 xxx&#xff0c;因为它来自身份不明…

旋翼式水表安装注意事项

旋翼式水表是一种常用的水流计量设备&#xff0c;适用于小口径管道的单向水流总量的计量。如果你正在考虑安装旋翼式水表&#xff0c;以下是一些需要注意的事项&#xff1a; 1.安装位置的选择&#xff1a;旋翼式水表应该安装在管道的垂直方向上&#xff0c;并且水流方向必须与水…

探秘ArrayList源码:Java动态数组的背后实现

探秘ArrayList源码&#xff1a;Java动态数组的背后实现 一、成员变量二、构造器1、默认构造器2、带初始容量参数构造器3、指定collection元素参数构造器 三、add()方法扩容机制四、场景分析1、对于ensureExplicitCapacity&#xff08;&#xff09;方法1.1 add 进第 1 个元素到 …

MQTT的理解和使用

MQTT是一种基于发布/订阅模式的轻量协议&#xff0c;该协议基于TCP/IP协议上&#xff0c;由IBM在1999年发布。 流程理解&#xff1a;订阅者在订阅时会选择主题&#xff08;Topic&#xff09;和服务质量&#xff08;QoS&#xff09;&#xff0c;然后发布者发布消息&#xff0c…

matlab超前-滞后校正

1控制系统的校正 系统性能 稳定性、准确性、快速性 动态性能-超前校正 阶跃曲线、频域&#xff08;bode图&#xff09;、根轨迹&#xff08;增加零点-根轨迹左移稳定性提高&#xff09;、PID控制&#xff08;PD&#xff09; 静态性能-滞后校正 阶跃曲线、频域&#xff08…