C语言:树

在C语言中,树(Tree)是一种常见的数据结构,用于表示分层关系或层次结构的数据集合。树在计算机科学中广泛应用,包括但不限于文件系统、解析表达式、数据压缩、决策树等。

1. 基本概念

  • 节点(Node):树的基本组成单元。每个节点包含数据和指向子节点的指针。
  • 根节点(Root Node):树的顶部节点,没有父节点。
  • 叶子节点(Leaf Node):没有子节点的节点。
  • 父节点(Parent Node):有子节点的节点。
  • 子节点(Child Node):有父节点的节点。
  • 兄弟节点(Sibling Nodes):拥有同一父节点的节点。
  • 树的高度(Height):从根节点到最深的叶子节点的路径中节点的最大数目。
  • 树的深度(Depth):从根节点到某个节点的路径长度。

2. 树的类型

  • 二叉树(Binary Tree):每个节点最多有两个子节点(左子节点和右子节点)。
  • 完全二叉树:除了最下层外,每一层都是满的,并且最下层的节点都靠左排列。
  • 满二叉树:所有层都完全填满。
  • 平衡二叉树:任意节点的左右子树的高度差不超过1。
  • 多叉树(N-ary Tree):每个节点可以有多个子节点。
  • 二叉搜索树(Binary Search Tree, BST):是一种特殊的二叉树,左子树所有节点的值小于根节点,右子树所有节点的值大于根节点。
  • AVL树:一种自平衡的二叉搜索树,确保树的左右子树的高度差不超过1。
  • 红黑树:一种自平衡的二叉搜索树,满足特定条件以保证树的高度不超过2log(n)。

3. 树的操作

  • 创建树:分配内存并初始化节点。
  • 插入:将新节点插入到树的适当位置。
  • 删除:从树中删除节点。
  • 遍历:访问树的每个节点,可以是先序、中序、后序、层序遍历等。
  • 搜索:在树中查找特定值的节点。

4. C语言实现

  • 定义
    • 在C语言中,树通常通过定义节点结构体来实现。例如,一个简单的二叉树节点可以这样定义:
// 定义树的节点结构
typedef struct TreeNode {
    int data; // 数据域
    struct TreeNode *left;  // 左子节点
    struct TreeNode *right; // 右子节点
} TreeNode;

然后,可以通过递归或非递归的方式来实现树的各种操作。

  • 创建节点
    • 动态分配内存为节点赋值:
TreeNode* createNode(int data) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode == NULL) {
        printf("内存分配失败\n");
        return NULL;
    }
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}
  • 插入节点(以二叉搜索树为例)
TreeNode* insert(TreeNode* root, int data) {
    if (root == NULL) {
        return createNode(data); // 根节点为空,创建新节点
    }
    if (data < root->data) {
        root->left = insert(root->left, data); // 插入到左子树
    } else {
        root->right = insert(root->right, data); // 插入到右子树
    }
    return root;
}
  • 遍历树
    • 前序遍历(Preorder)
      访问顺序:根 -> 左 -> 右
void preorderTraversal(TreeNode* root) {
    if (root != NULL) {
        printf("%d ", root->data);          // 访问根节点
        preorderTraversal(root->left);     // 遍历左子树
        preorderTraversal(root->right);    // 遍历右子树
    }
}
  • 中序遍历(Inorder)
    • 访问顺序:左 -> 根 -> 右
void inorderTraversal(TreeNode* root) {
    if (root != NULL) {
        inorderTraversal(root->left);      // 遍历左子树
        printf("%d ", root->data);         // 访问根节点
        inorderTraversal(root->right);     // 遍历右子树
    }
}
  • 后序遍历(Postorder)
    访问顺序:左 -> 右 -> 根
void postorderTraversal(TreeNode* root) {
    if (root != NULL) {
        postorderTraversal(root->left);    // 遍历左子树
        postorderTraversal(root->right);   // 遍历右子树
        printf("%d ", root->data);         // 访问根节点
    }
}
  • 释放树的内存
    • 为了避免内存泄漏,必须递归释放所有节点:
void freeTree(TreeNode* root) {
    if (root != NULL) {
        freeTree(root->left);  // 释放左子树
        freeTree(root->right); // 释放右子树
        free(root);            // 释放当前节点
    }
}

5. 示例

以下是一个基于C语言实现的二叉搜索树(Binary Search Tree, BST)的案例。这个例子包含了创建树、插入节点、删除节点、搜索节点和遍历树的基本操作:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

// 定义树节点结构体
struct TreeNode {
    int data;
    struct TreeNode *left;
    struct TreeNode *right;
};

// 创建一个新节点
struct TreeNode* createNode(int value) {
    struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    newNode->data = value;
    newNode->left = newNode->right = NULL;
    return newNode;
}

// 插入操作
struct TreeNode* insert(struct TreeNode* root, int value) {
    // 如果树为空,新建一个根节点
    if (root == NULL) return createNode(value);

    // 否则,递归找到插入位置
    if (value < root->data)
        root->left = insert(root->left, value);
    else if (value > root->data)
        root->right = insert(root->right, value);

    return root;
}

// 中序遍历(Inorder Traversal)
void inorderTraversal(struct TreeNode* root) {
    if (root != NULL) {
        inorderTraversal(root->left);
        printf("%d ", root->data);
        inorderTraversal(root->right);
    }
}

// 搜索节点
struct TreeNode* search(struct TreeNode* root, int key) {
    // 如果树为空或者当前节点就是要找的节点
    if (root == NULL || root->data == key)
       return root;

    // 递归查找
    if (root->data < key)
       return search(root->right, key);

    return search(root->left, key);
}

// 找到最小值的节点
struct TreeNode* minValueNode(struct TreeNode* node) {
    struct TreeNode* current = node;

    // 循环找到最左边的叶子节点
    while (current && current->left != NULL)
        current = current->left;

    return current;
}

// 删除节点
struct TreeNode* deleteNode(struct TreeNode* root, int key) {
    // 如果树为空
    if (root == NULL) return root;

    // 否则,递归找到要删除的节点
    if (key < root->data)
        root->left = deleteNode(root->left, key);
    else if (key > root->data)
        root->right = deleteNode(root->right, key);
    else {
        // 节点有0个或1个子节点
        if (root->left == NULL) {
            struct TreeNode *temp = root->right;
            free(root);
            return temp;
        } else if (root->right == NULL) {
            struct TreeNode *temp = root->left;
            free(root);
            return temp;
        }

        // 节点有两个子节点,获取右子树中的最小节点
        struct TreeNode* temp = minValueNode(root->right);

        // 将该最小节点的数据复制到当前节点
        root->data = temp->data;

        // 删除右子树中的最小节点
        root->right = deleteNode(root->right, temp->data);
    }
    return root;
}

// 释放树的内存
void freeTree(struct TreeNode* root) {
    if (root != NULL) {
        freeTree(root->left);
        freeTree(root->right);
        free(root);
    }
}

// 主函数
int main() {
    struct TreeNode* root = NULL;
	SetConsoleOutputCP(65001);     //设置控制台程序输出的代码页编码为utf-8格式,否则,中文会出现乱码
    root = insert(root, 50);
    insert(root, 30);
    insert(root, 20);
    insert(root, 40);
    insert(root, 70);
    insert(root, 60);
    insert(root, 80);

    printf("中序遍历结果:\n");
    inorderTraversal(root);
    printf("\n");

    int key = 20;
    struct TreeNode* res = search(root, key);
    if(res != NULL)
        printf("找到值 %d\n", key);
    else
        printf("未找到值 %d\n", key);

    root = deleteNode(root, 20);
    printf("删除20后,中序遍历结果:\n");
    inorderTraversal(root);
    printf("\n");

    // 释放树的内存
    freeTree(root);

    return 0;
}

  • 这个例子展示了如何创建一个二叉搜索树、插入节点、搜索特定值的节点、删除节点以及遍历树。它还包括了如何在程序结束时释放树的内存以避免内存泄漏。
  • 运行:
    在这里插入图片描述

6. 总结

  • 树是一种重要的数据结构,支持递归操作,常用于表示层次化数据。
  • 在 C 语言中实现树通常需要动态分配内存,使用递归操作处理节点。
  • 避免内存泄漏是树实现中的关键点,需要显式释放节点内存。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python写的服务,用docker制作镜像并且打包

步骤1 简单写一个python服务脚本app.py&#xff0c;通过http访问一个端口&#xff0c;收到helloworld from flask import Flask, request app Flask(__name__) app.route(/, methods[GET]) # 确保包括GET方法 def hello_world(): return Hello, World! if __name__ __main…

NSSCTF web刷题

1 虽然找到了flag,但是我要怎么去改他的代码,让他直接输出flag呢? (好像是要得到他的json代码,这题不让看) 2 wllm应该就是他的密码,进入许可了 意思是服务器可以执行通过POST的请求方式传入参数为wllm的命令&#xff0c;那这就是典型的命令执行&#xff0c;当然&#xff0c…

(0基础保姆教程)-JavaEE开课啦!--11课程(初识Spring MVC + Vue2.0 + Mybatis)-实验9

一、什么是Spring MVC&#xff1f; Spring MVC 是一个基于 Java 的 Web 框架&#xff0c;遵循 MVC 设计模式&#xff0c;用于构建企业级应用程序。它通过控制器(Controller)处理用户请求&#xff0c;模型(Model)处理业务逻辑&#xff0c;视图(View)展示数据&#xff0c;实现了请…

FCBP 认证考试要点摘要

理论知识 数据处理与分析&#xff1a;包括数据的收集、清洗、转换、存储等基础操作&#xff0c;以及数据分析方法&#xff0c;如描述性统计分析、相关性分析、数据挖掘算法等的理解和应用 。数据可视化&#xff1a;涉及图表类型的选择与应用&#xff0c;如柱状图、折线图、饼图…

「Qt Widget中文示例指南」如何为窗口实现流程布局?(二)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 本文将展示如何为不…

智能产品综合开发 - 手势识别

1 实训选题目的 本次实训选择的题目是“基于树莓派的手势识别系统”&#xff0c;旨在为人们提供一种便捷的交互方式&#xff0c;使用户能够通过手势控制智能设备&#xff0c;摆脱传统的物理按键操作。通过本项目&#xff0c;我们希望能实现快速、灵活的手势识别&#xff0c;提升…

Redis【1】- 如何阅读Redis 源码

1 Redis 的简介 Redis 实际上是简称&#xff0c;全称为 Remote Dictionary Server (远程字典服务器)&#xff0c;由 Salvatore Sanfilippo 写的高性能 key-value 存储系统&#xff0c;其完全开源免费&#xff0c;遵守 BSD 协议。Redis 与其他 key-value 缓存产品&#xff08;如…

git的使用(简洁版)

什么是 Git&#xff1f; Git 是一个分布式版本控制系统 (DVCS)&#xff0c;用于跟踪文件的更改并协调多人之间的工作。它由 Linus Torvalds 在 2005 年创建&#xff0c;最初是为了管理 Linux 内核的开发。Git 的主要目标是提供高效、易用的版本控制工具&#xff0c;使得开发者…

用于高吞吐量和低延迟的 JVM 性能调优

Java 虚拟机 &#xff08;JVM&#xff09; 调优是调整默认参数以满足我们的应用程序需求的过程。这包括通过选择合适的垃圾回收器来使用优化版本的 getter 来调整堆的大小等简单调整。 了解 Java 虚拟机 &#xff08;JVM&#xff09; 什么是 JVM&#xff1f; Java 虚拟机 &…

django authentication 登录注册

文章目录 前言一、django配置二、后端实现1.新建app2.编写view3.配置路由 三、前端编写1、index.html2、register.html3、 login.html 总结 前言 之前&#xff0c;写了django制作简易登录系统&#xff0c;这次利用django内置的authentication功能实现注册、登录 提示&#xff…

Python+Pytest+Yaml+Allure数据参数化(DDT)数据驱动(一)

我们在做数据之前要知道几个问题 1、在代码层面怎么来数据驱动 2、yaml文件是什么 3、怎么用yaml文件实现对应的数据驱动 我们用的是pytest框架所以相对来说是简单的&#xff0c;我们通过pytest框架来实现&#xff0c;而框架中要数据驱动用到我们装饰器就好啦pytest.mark.p…

WaveForms™ SDK 参考手册(翻译笔记与总结)

概述 WaveForms 提供了一个接口&#xff0c;允许用户与 Digilent Analog Design 硬件进行交互&#xff0c;例如 Analog DiscoveryTM、Analog Discovery 2TM、Analog Discovery ProTM、Digital DiscoveryTM、Discovery Power SupplyTM 和 Electronics ExplorerTM。虽然 WaveForm…

Python基础学习-12匿名函数lambda和map、filter

目录 1、匿名函数&#xff1a; lambda 2、Lambda的参数类型 3、map、 filter 4、本节总结 1、匿名函数&#xff1a; lambda 1&#xff09;语法&#xff1a; lambda arg1, arg2, …, argN : expression using arg 2&#xff09; lambda是一个表达式&#xff0c;而不是一个语…

pyqt5+yolo模型+多线程

界面开发 开发主窗口界面 from PyQt5 import QtWidgets from PyQt5 import QtCore,QtGui import sysclass MainWindow(QtWidgets.QMainWindow):def __init__(self):super().__init__()self.initUI()self.toolbar()# 创建菜单栏def initUI(self):menubar self.menuBar()file_m…

交通流量预测:基于交通流量数据建立模型

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

[Java]微服务配置管理

介绍 代码拆分为微服务后, 每个服务都有自己的配置文件, 而这些配置文件中有很多重复的配置, 并且配置变化后需要重启服务, 才能生效, 这样就会影响开发体验和效率 配置管理服务可以帮助我们集中管理公共的配置, 并且nacos就可以实现配置管理服务 配置共享 我们可以把微服务共…

【C++】入门【三】

本节目标 一、类的6个默认成员函数 二、 构造函数 三、析构函数 四、拷贝构造函数 五、赋值运算符重载 六、const成员函数 七、取地址及const取地址操作符重载 一、类的6个默认成员函数 如果类里一个成员都没有&#xff0c;简称空类空类中真的什么都没有吗&#xff1f;并不不是…

D78【 python 接口自动化学习】- python基础之HTTP

day78 pycharm创建项目并进行接口请求 学习日期&#xff1a;20241124 学习目标&#xff1a;http定义及实战 -- pycharm创建项目并进行接口请求 学习笔记&#xff1a; 安装requests 安装方式&#xff1a;pip/pip3 install requests 官网教程&#xff1a;Requests: HTTP fo…

UE5 实现组合键触发事件的方法

因为工作原因。 需要用大括号{和}来触发事件 但是在蓝图中搜了一下&#xff0c;发现键盘事件里根本就没有{}这两个键。 花费了一下午&#xff0c;终于找到解决的方法了&#xff0c;也就是增强输入的弦操作 首先创建一个项目 纯蓝图或者C都可行 进入到内容浏览器的默认页面 …

rabbitmq原理及命令

目录 一、RabbitMQ原理1、交换机&#xff08;Exchange&#xff09;fanoutdirecttopicheaders&#xff08;很少用到&#xff09; 2、队列Queue3、Virtual Hosts4、基础对象 二、RabbitMQ的一些基本操作:1、用户管理2、用户角色3、vhost4、开启web管理接口5、批量删除队列 一、Ra…