c语言(二叉树)

news2024/11/25 10:47:11

第4章 二叉树和BST

树与二叉树

  1. 基本概念

    • 树是一种非线性结构,其严格的数学定义是:如果一组数据中除了第一个节点(第一个节点称为根节点,没有直接前驱节点)之外,其余任意节点有且仅有一个直接前驱,有零个或多个直接后继,这样的一组数据形成一棵树。这种特性简称为一对多的逻辑关系。即用于描述具有层次关系,类似组织架构关系的一种数据结构。
      在这里插入图片描述
    • 树的组成:根,分支,叶子
  2. 常见例子

    • 日常生活中,很多数据的组织形式本质上是一棵树。比如一个公司中的职员层级关系,一个学校中的院系层级关系,淘汰赛中的各次比赛队伍,一个家族中的族谱成员关系等,这些都是树状逻辑结构。由于树状结构表现出来都是具有层次的,因此也被称为层次结构。
      在这里插入图片描述
  3. 相关术语

    • 通常,在逻辑上表达一棵抽象的树状结构的时候,习惯于将树根放在顶部,树枝树杈向下生长,如下图所示。
      在这里插入图片描述

    • 对于一棵树来说,有如下基本术语:

      • 结点:树中的元素及其子树。
      • 根(root):树的第一个节点,没有直接前驱。如上图中的A。
      • 双亲节点/父节点(parent):某节点的直接前驱称为该节点的双亲节点,或成为父节点。例如上图中A是B的父节点。
      • 孩子节点/子节点(child):某节点的直接后继称为该节点的孩子节点。例如上图中B、C、D均为A的孩子节点。
      • 节点的层次(level):根节点所在的层次规定为第1层,其孩子所在的层次为第2层,后代节点以此类推。比如上图中节点E的层次是3。
      • 节点的度(degree):一个节点拥有的孩子节点的总数,称为该节点的度。比如上图中节点B的度为2。
      • 叶子(leaf):一棵树中度等于0的节点,被称为叶子,又称为终端节点。比如上图中K、L、F、G、M、I、J均为叶子。
      • 树的高度(height):一棵树中所有节点的层次的最大值,称为这棵树的高度,又称为树的深度。比如上图的树的高度为4。
      • 有序树与无序树:一棵树中,如果某个节点的孩子节点之间是有次序的,则称这棵树为有序树,反之称为无序树。

二叉树

  1. 定义

    • 在各种不同的树状结构中,最常见也最重要的是二叉树(Binary Tree),下面是二叉树的定义:
    • 有序树,任意节点的度小于等于2。
    • 比如如下这棵树就是一棵二叉树。其中8是根节点,14是10的右孩子(因为二叉树是有序树,因此严格区分左右),而13则是14的左孩子。
      在这里插入图片描述
  2. 特性

    • 第𝑖层上,最多有2𝑖−1个节点。
    • 高度为𝑘的二叉树,最多有2𝑘−1个节点。
    • 假设叶子数目为𝑛0,度为2的节点数目为𝑛2,则有:

二叉树的一般结构

  1. 满二叉树

    • 一棵深度为k,且有2^k - 1个结点的二叉树,称为满二叉树。这种树的特点是每一层上的结点数都是最大结点数。
    • 简单理解:除了叶子节点之外,其余节点的度都为2;其特点是:如果深度为 K,则节点数为 2^K - 1。
      在这里插入图片描述
  2. 完全二叉树

    • 在一棵二叉树中,除最后一层外,若其余层都是满的,或者最后一层是满的,或者是最后一层在右边缺少连续若干结点,则此二叉树为完全二叉树。
    • 简单理解:除最后一层叶子节点外。是一颗满二叉树,最后一层由右向左有连续缺省的0个,1个或多个节点。
      在这里插入图片描述

二叉搜索树(BST)

  1. 特点

    • 如果节点具有左子树,则左子树上所有节点都不大于该节点的值;
    • 节点具有右子树,则右子树上所有节点都不小于该节点的值;
    • 子树又是二叉搜索数。
      在这里插入图片描述
  2. 逻辑上的 内存中的

    • 二叉树 二叉树
  3. 二叉搜索树(BST)的组成

    • 根指针:指向根节点的指针变量。
    • 节点
      • 数据域(存储的实际数据)
      • 指针域 (左,右指针)

结构设计

typedef int data_t;

typedef struct _node
{
    data_t data; // 数据域
    struct _node *left; // 左子树指针
    struct _node *right;// 右子树指针
}NODE;

二叉树 (BST) 的算法

  1. 创建二叉树
int btree_create(NODE** root, data_t data);
  1. 二叉树数据添加
int btree_add(NODE** root, data_t data);
  1. 示例图
    在这里插入图片描述

二叉树数据遍历

  1. 前序遍历 (先序遍历,即 根左右)
void Preorder(const NODE* root);
  • 前序遍历通俗的说就是从二叉树的根结点出发,先输出根结点数据,然后输出左结点,最后输出右结点的数据。
    在这里插入图片描述

  • 从根结点出发,则第一次到达结点 A,故输出 A;继续向左访问,第一次访问结点 B,故输出 B;按照同样规则,输出 D,输出 H;当到达叶子结点 H,返回到 D,此时已经是第二次到达 D,故不在输出 D,进而向 D 右子树访问,D 右子树不为空,则访问至 I,第一次到达 I,则输出 I;I 为叶子结点,则返回到 D,D 左右子树已经访问完毕,则返回到 B,进而到 B 右子树,第一次到达 E,故输出 E;向 E 左子树,故输出 J;按照同样的访问规则,继续输出 C、F、G。

  • 前序遍历输出结果:ABDHIEJCFG

  1. 中序遍历 (即 左根右)
void Midorder(const NODE* root);
  • 中序遍历通俗的说就是从二叉树的根结点出发,先输出左结点数据,然后输出根结点,最后输出右结点的数据。
    -在这里插入图片描述

  • 从根结点出发,则第一次到达结点 A,不输出 A,继续向左访问,第一次访问结点 B,不输出 B;继续到达 D,H;

  • 到达 H,H 左子树为空,则返回到 H,此时第二次访问 H,故输出 H;H 右子树为空,则返回至 D,此时第二次到达 D,故输出 D;由 D 返回至 B,第二次到达 B,故输出 B;按照同样规则继续访问,输出 J、E、A、F、C、G;

  • 中序遍历输出结果:HDIBJEAFCG

  1. 后序遍历 (即 左右根)
void Postorder(const NODE* root);
  • 后序遍历通俗的说就是从二叉树的根结点出发,先输出左结点数据,然后输出右结点,最后输出根结点的数据。
    在这里插入图片描述

  • 从根结点出发,则第一次到达结点 A,不输出 A,继续向左访问,第一次访问结点 B,不输出 B;继续到达 D,H;

  • 到达 H,H 左子树为空,则返回到 H,此时第二次访问 H,不输出 H;H 右子树为空,则返回至 H,此时第三次到达 H,故输出 H;由 H 返回至 D,第二次到达 D,不输出 D;继续访问至 I,I 左右子树均为空,故第三次访问 I 时,输出;返回至 D,此时第三次到达 D,故输出 D;按照同样规则继续访问,输出 J、E、B、F、G、C,A;

  • 后序遍历输出为:HIDJEBFGCA

  1. 层序遍历
void Levelorder(const NODE* root);

二叉树数据查询

NODE* btree_find(const NODE* root, data_t data);
  1. 从根结点出发
  2. 如果比根节点小,那么就去其左子树找
  3. 如果比根节点大就去其右子树找
  4. 找到叶子都没找到, 就代表查找失败
    在这里插入图片描述

二叉树数据更新

隐藏过程

复制

int btree_update(const NODE* root, data_t old, data_t newdata);

二叉树回收

隐藏过程

复制

void btree_destroy(NODE** root);

二叉树数据删除

  1. 原则:将待删除的节点尽量转换为删除叶子节点,因为删除叶子节点对 BST 树影响是最小的。

  2. 思路

    • int btree_delete(NODE** root, data_t data);
    • 从根节点开始遍历 BST 找到待删除的节点;
    • 对待删除的节点状态进行判断,如果节点有左子树,找到左子树中最大的节点,然后利用左子树中最大的节点数据替换待删除的节点数据,删除左子树中最大的节点;左子树中最大的节点大概率是叶子节点。
    • 如果节点只有右子树,找到右子树中最小的节点,然后利用右子树中最小的节点数据替换待删除的节点数据,删除右子树中最小的节点;右子树中最小的节点大概率是叶子节点。
    • 如果待删除节点是叶子节点,直接删除。

二叉树 (BST) 完整实现

队列实现

SQueue.h
#ifndef __SQUEUE_H
#define __SQUEUE_H

#include "btree.h"

typedef NODE* type_t;

typedef struct
{
    type_t *pData;
    int size;
    int head;![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/df354bd58cc5428aa589a2e8aae6fada.png#pic_center)

    int tail;
}SQueue;

int SQ_init(SQueue *q, int num);
int SQ_isfull(SQueue *q);
int SQ_isempty(SQueue *q);
int SQ_push(SQueue *q, type_t data);
int SQ_pop(SQueue *q, type_t *data);
int SQ_free(SQueue *q);
#endif
SQueue.c
#include <stdlib.h>
#include "SQueue.h"

int SQ_init(SQueue* q, int num)
{
    q -> pData = (type_t*)calloc(sizeof(type_t), num);
    if(q -> pData == NULL)
        return -1;

    q -> size = num;
    q -> head = q -> tail = 0;
    return 0;
}

int SQ_isfull(SQueue *q)
{
    return (q -> tail + 1) % q -> size == q -> head;
}

int SQ_isempty(SQueue *q)
{
    return q -> tail == q -> head;
}

int SQ_push(SQueue *st, type_t data)
{
    if(SQ_isfull(st))
        return -1;

    st -> pData[st -> tail] = data;
    st -> tail = (st -> tail + 1) % st -> size;
    return 0;
}

int SQ_pop(SQueue *st, type_t *data)
{
    if(SQ_isempty(st))
        return -1;

    *data = st -> pData[st -> head];
    st -> head = (st -> head + 1) % st -> size;

    return 0;
}

int SQ_free(SQueue *st)
{
    if(st -> pData)
    {
        free(st->pData);
        st -> pData = NULL;
    }

    st -> head = st -> tail = 0; 
}

树的实现

btree.h
#ifndef __BTREE_H
#define __BTREE_H

typedef int data_t;

typedef struct _node
{
    data_t data; // 节点上的数据
    struct _node *left; // 该节点左侧子节点的地址
    struct _node *right;// 该节点右侧子节点的地址
}NODE;

// 创建搜索二叉树
int btree_create(NODE** root, data_t data);
// 二叉树数据添加
int btree_add(NODE** root, data_t data);
// 二叉树数据删除
int btree_delete(NODE** root, data_t data);

// 二叉树前序遍历
void Preorder(const NODE* root);
// 二叉树中序遍历
void Midorder(const NODE* root);
// 二叉树后序遍历
void Postorder(const NODE* root);
// 二叉树层序遍历
void Levelorder(const NODE* root);
// 二叉树数据查询
NODE* btree_find(const NODE* root, data_t data);
// 更新二叉树数据old 为 newdata
int btree_update(const NODE* root, data_t old, data_t newdata);
// 二叉树回收
void btree_destroy(NODE** root);

#endif
btree.c
#include "btree.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "SQueue.h"

@function: int btree_create(NODE** root, data_t data)
@function:
@ret
@function :
@ret
@brief: 创建搜索二叉树
@argument: root: 根指针地址
@argument: data: 存储的数据
成功
-1 失败

int btree_create(NODE** root, data_t data)
{
    if(*root)
        return -1;

    NODE* p = (NODE*)malloc(sizeof(NODE));
    if(!p)
        return -1;

    p -> data = data;
    p -> left = NULL;
    p -> right = NULL;

    *root = p;
    return 0;
}

/*
@function: int btree_add(NODE** root, data_t data)
@brief: 二叉树数据添加
@argument: root: 根指针地址
@argument: data: 添加的数据
成功
-1 失败
*/
int btree_add(NODE** root, data_t data)
{
    NODE* pNew = (NODE*)malloc(sizeof(NODE));
    if(!pNew)
        return -1;

    pNew -> data = data;
    pNew -> left = NULL;
    pNew -> right = NULL;

    NODE* p = *root;
    if(!p)
    {
        *root = pNew;
        return 0;
    }

    while(p)
    {
        NODE* q = p;
        if(memcmp(&data, &(p -> data), sizeof(data_t)) < 0)
            p = p -> left;
        else
            p = p -> right;

        if(memcmp(&data, &(q -> data), sizeof(data_t)) < 0)
            q -> left = pNew;
        else
            q -> right = pNew;
    }

    return 0;
} 

/*
@function: int btree_delete(NODE** root, data_t data)
@brief: 二叉树数据删除
@argument: root: 根指针地址
@argument: data: 待删除的节点数据
成功
-1 失败
*/
int btree_delete(NODE** root, data_t data)
{
    /*
    原则:

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

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

相关文章

macos 10.15 catalina xcode 下载和安装

在macos 10.15 catalina系统中, 由于系统已经不再支持,所以我们无法通过应用商店来安装xcode, 需要手动下载指定版本的 xcode 版本才能安装, catalina 支持的最新xcode版本为 Xcode v12.4 (12D4e) , 其他的新版本是无法安装在Catalina系统中的. Xcode_12.4.xip下载地址 注意,下…

安装虚拟机(VMware)教程

VMware-虚拟机使用 一、VMware 介绍二、VMware 下载三、VMware 安装1.第一步&#xff0c;点击安装的*.exe文件&#xff0c;出现以下画面2.第二步&#xff0c;点击下一步&#xff0c;到选择安装的路径&#xff0c;默认安装和自定义安装3.第三步&#xff0c;点击安装&#xff0c;…

postgresql底层Driver驱动包数据库是怎么连接,怎么发送数据,怎么设置超时

##一、建立连接 ##connectionFactory.openConnectionImpl ##底层也没什么神秘的&#xff0c;就是使用的socket通讯 ##连接&#xff0c;打开流 ##socket.connect ##获取到读写流 ##二、数据库连接池创建Connection连接 ##三、发送相关sql数据 ##发数据 ##发送查询 ##sendParse(q…

nefu暑假acm集训1 构造矩阵 个人模板+例题汇总

前言&#xff1a; 以下都是nefu暑假集训的训练题&#xff0c;我在此把我的模板和写的一些练习题汇总一下并分享出来&#xff0c;希望在能满足我复习的情况下能帮助到你。 正文&#xff1a; 模板&#xff1a; #include<bits/stdc.h> using namespace std; typedef long…

手机三网状态实时查询分享

我们演示如何使用Python对接手机号在网状态API接口 以下是详细的接口文档&#xff1a;https://www.tanshuapi.com/market/detail-123 首先&#xff0c;您需要注册并获取API密钥。假设您已经拥有API密钥&#xff0c;接下来是具体的实现步骤。 编写Python代码 以下是一个Python…

如何使用Gogs搭建自己的git服务器

最近偶然发现一款轻量级的git服务器&#xff0c;以前一直用的svn server&#xff0c;最近想搞个git服务器&#xff0c; 用gitlab资源占用太多了&#xff0c;gogs是一款轻量级git服务器&#xff0c;非常适合个人使用。 项目地址&#xff1a;GitHub - gogs/gogs: Gogs is a painl…

隔离电源不能与其他电源共地吗

隔离电源通常设计用于在电气系统中提供安全隔离&#xff0c;以避免不同部分之间的电流回路和潜在的电气干扰。隔离电源的一个关键特点是其输出端与输入端之间没有直接的电气连接&#xff0c;而是通过变压器、光电耦合器或其他隔离手段实现。 关于隔离电源与其他电源共地的问题&…

神神叨叨的OpenAI和神神叨叨的草莓

其实现在的OpenAI挺烦人的&#xff0c;和之前Ilya在的时候就不太一样了&#xff0c;Schulman也走了, 尤其Schulman走了是真的可惜&#xff0c;因为他是整个后训练&#xff0c;包括微调尤其是RLHF的真正操盘手 Altman发草莓然后又没下文&#xff0c;挺败好感的&#xff0c;大家…

Ubuntu安装交叉编译工具链(gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu)

1&#xff1a; 首先把压缩包解压出来 2&#xff1a; 我是把文件名字进行了修改&#xff0c;这个看个人需求。终端输入&#xff1a; sudo vim .bashrc在文件最末尾输入&#xff1a; export PATH$PATH:/home/the/aarch64-linux-gnu/bin export LD_LIBRARY_PATH$LD_LIBRARY_PAT…

合合信息acge模型获C-MTEB第一,文本向量化迎来新突破

前言&#xff1a; 在当今时代&#xff0c;大型语言模型以其惊人的发展速度和广泛的应用前景&#xff0c;正成为全球科技界的瞩目焦点。这些模型的强大能力&#xff0c;源自于背后默默支撑它们的Embedding技术——一种将语言转化为机器可理解的数值向量的关键技术。随着大型语言…

05:创建逻辑软件元件库

1.创建逻辑软件元件库 点击 “编辑电参数” 1.1常规设置 1.2PCB封装 1.3门 1.4管脚 1.5检查元件 点击确定 1.6点击保存 2.处理重叠问题 2.1查看处理后的显示

【Linux】:用户缓冲区

1.前言&#xff08;引出现象&#xff09; 我们看一段代码&#xff0c; 我们运行这段代码&#xff0c; 再次运行&#xff0c;并将打印结果重定向到文件log.txt中&#xff0c; 结果除了系统调用write的输出&#xff0c;其余输出都多打印一次。这是为什么呢&#xff1f;我们先…

IO进程线程 0829作业

作业 1、将消息队列发送接收端实现一遍。 send.c代码 #include <myhead.h>struct msgbuf {long mtype; /* 消息的类型*/char mtext[1000]; /* 消息的正文&#xff0c;长度不是1&#xff0c;可以自定义*/ };#define leng sizeof(struct msgbuf) - sizeof(long…

2022 年高教社杯全国大学生数学建模竞赛-C 题 古代玻璃制品的成分分析与鉴别详解+分类模型Python代码源码

前言 简单介绍一下我自己&#xff1a;博主专注建模四年&#xff0c;参与过大大小小数十来次数学建模&#xff0c;理解各类模型原理以及每种模型的建模流程和各类题目分析方法。参与过十余次数学建模大赛&#xff0c;三次美赛获得过二次M奖一次H奖&#xff0c;国赛二等奖。**提…

leetcode120. 三角形最小路径和,二维动态规划

leetcode120. 三角形最小路径和 给定一个三角形 triangle &#xff0c;找出自顶向下的最小路径和。 每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 1 的两个结点。也就是说&#xff0c;如果正位于当前…

STM32-PWM驱动舵机——HAL库

什么是舵机&#xff1f; 舵机&#xff0c;也叫伺服电机&#xff0c;在嵌入式开发中&#xff0c;舵机作为一种常见的运动控制组件&#xff0c;具有广泛的应用。 舵机型号介绍&#xff1a; 市面上常见的舵机型号有 SG90、MG90S、MG995、MG996R 等等&#xff0c;主要是扭矩大小…

Linux--IO多路复用(select,poll,epoll)

IO多路复用——select&#xff0c;poll&#xff0c;epoll IO多路复用是一种操作系统技术&#xff0c;旨在提高系统处理多个输入输出操作的性能和资源利用率。与传统的多线程或多进程模型相比&#xff0c;IO多路复用避免了因阻塞IO而导致的资源浪费和低效率问题。它通过将多个IO…

使用matplotlib可视化dataframe:让你的数据更生动有趣

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 1. 简介 在数据分析和可视化领域&#xff0c;matplotlib是一个非常强大的工具。它可以帮助将数据以图形的形式展示出来&#xff0c;使得数据更加直观、易于理解。本文将介绍如何使用matplotlib来可视化pandas中的Da…

小q的数列(c语言)

1./描述 //小q最近迷上了各种好玩的数列&#xff0c;这天&#xff0c;他发现了一个有趣的数列&#xff0c;其递推公式如下&#xff1a; // //f[0] 0 f[1] 1; //f[i] f[i / 2] f[i % 2]; (i > 2) // //现在&#xff0c;他想考考你&#xff0c;问&#xff1a;给你一个n&am…

趣映 v2.3.8 — 高级版,专注动画制作,自媒体变现

趣映是一款专注于为动画垂直账号提供全面视频编辑和制作功能的软件&#xff0c;支持从灵感创作到成片输出的全流程。海量模板助您一键制作爆款动画视频和动漫视频&#xff0c;适配各种场景。此版本已解锁高级功能&#xff0c;提供更丰富的编辑工具和模板。 链接&#xff1a;ht…