1 概述
1.1 案例介绍
在C语言中,树是一种非线性数据结构,由节点(node)组成层级关系,每个节点包含数据及指向子节点的指针,起始于根节点(root),分支至子节点,终结于叶节点(leaf)。二叉树是其特例,每个节点至多有两个子节点:左子节点(left)和右子节点(right)。二叉树支持高效操作,如二叉搜索树(BST)用于快速查找;遍历方式包括前序(根-左-右)、中序(左-根-右)和后序(左-右-根),广泛应用于数据存储、排序及算法设计。
本案例相关实验将在华为云开发者空间云主机进行,开发者空间云主机为开发者提供了高效稳定的云资源,确保用户的数据安全。云主机当前已适配完整的C/C++开发环境,支持VS Code等多种IDE工具安装调测。
1.2 适用对象
- 个人开发者
- 高校学生
1.3 案例时间
本案例总时长预计40分钟。
1.4 案例流程
{{{width="50%" height="auto"}}}
说明:
- 开通开发者空间,搭建C/C++开发环境。
- 打开VS Code,编写代码运行程序。
1.5 资源总览
本案例预计花费总计0元。
| 资源名称 | 规格 | 单价(元) | 时长(分钟) |
|---|---|---|---|
| 开发者空间-云主机 | 4vCPUs | 8GB | ARM/鲲鹏 | Ubuntu | Ubuntu 24.04 Server 定制版 | 免费 | 40 |
| VS Code | 1.97.2 | 免费 | 40 |
2 配置实验环境
2.1 开发者空间配置
面向广大开发者群体,华为开发者空间提供一个随时访问的“开发桌面云主机”、丰富的“预配置工具集合”和灵活使用的“场景化资源池”,开发者开箱即用,快速体验华为根技术和资源。
如果还没有领取开发者空间云主机,可以参考免费领取云主机文档领取。
领取云主机后可以直接进入华为开发者空间工作台界面,点击打开云主机 > 进入桌面连接云主机。


2.2 配置实验环境
参考案例中心《基于开发者空间,定制C&C++开发环境云主机镜像》“2. 实验环境搭建”、“3. VS Code安装部署”章节完成开发环境、VS Code及插件安装。

3 树和二叉树
3.1 树的基本概念
树:是一种非线性的数据结构,它是由n(n≥0)个有限节点组成一个具有层次关系的集合。
树的术语:
节点:树中的每个元素
根节点:没有父节点的节点
子节点:一个节点含有的子树的根节点
父节点:若一个节点含有子节点,则该节点是其子节点的父节点
度:一个节点含有的子树的个数
叶子节点:度为0的节点
兄弟节点:具有相同父节点的节点
层次:根为第一层,根的子节点为第二层,以此类推
高度/深度:树中节点的最大层次
3.2 二叉树基础
二叉树:是每个节点最多有两个子树的树结构,通常称为左子树和右子树。
二叉树的性质:
- 第i层上至多有2\^(i-1)个节点;
- 深度为k的二叉树至多有2\^k - 1个节点;
- 对于任何二叉树,叶子节点数n0 = 度为2的节点数n2 + 1。
二叉树的代码实现:
#include <stdio.h>
#include <stdlib.h>
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");
exit(1);
}
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
int main() {
return 0;
}
3.3 二叉树的基本操作
插入节点:
具体代码操作如下:
Step1:复制以下代码,替换main.cpp文件中的代码。
#include <stdio.h>
#include <stdlib.h>
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");
exit(1);
}
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 if (data > root->data) {
root->right = insert(root->right, data);
}
return root;
}
int main() {
TreeNode* root = NULL;
printf("创建二叉树并插入数据: 50, 30, 20, 40, 70, 60, 80\n");
root = insert(root, 50);
root = insert(root, 30);
root = insert(root, 20);
root = insert(root, 40);
root = insert(root, 70);
root = insert(root, 60);
root = insert(root, 80);
return 0;
}
Step2:点击编辑器左上角运行按钮直接运行,Terminal窗口可以看到打印内容。

遍历二叉树:前序遍历、中序遍历、后序遍历、层次遍历。
前序遍历:访问顺序为根节点 -> 左子树 -> 右子树。
中序遍历:访问顺序为左子树 -> 根节点 -> 右子树。
后序遍历:访问顺序为左子树 -> 右子树 -> 根节点。
层次遍历:按层次从上到下,从左到右访问节点。
具体代码操作如下:
Step1:复制以下代码,替换main.cpp文件中的代码。
#include <stdio.h>
#include <stdlib.h>
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");
exit(1);
}
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 if (data > root->data) {
root->right = insert(root->right, data);
}
return root;
}
// 前序遍历
void preOrder(TreeNode* root) {
if (root != NULL) {
printf("%d ", root->data);
preOrder(root->left);
preOrder(root->right);
}
}
// 中序遍历
void inOrder(TreeNode* root) {
if (root != NULL) {
inOrder(root->left);
printf("%d ", root->data);
inOrder(root->right);
}
}
// 后序遍历
void postOrder(TreeNode* root) {
if (root != NULL) {
postOrder(root->left);
postOrder(root->right);
printf("%d ", root->data);
}
}
// 层次遍历(使用简单队列实现)
void levelOrder(TreeNode* root) {
if (root == NULL) return;
TreeNode* queue[100]; // 简单的队列实现
int front = 0, rear = 0;
queue[rear++] = root;
while (front < rear) {
TreeNode* current = queue[front++];
printf("%d ", current->data);
if (current->left != NULL) {
queue[rear++] = current->left;
}
if (current->right != NULL) {
queue[rear++] = current->right;
}
}
}
int main() {
TreeNode* root = NULL;
root = insert(root, 50);
root = insert(root, 30);
root = insert(root, 20);
root = insert(root, 40);
root = insert(root, 70);
root = insert(root, 60);
root = insert(root, 80);
printf("\n遍历二叉树:\n");
printf("前序遍历: ");
preOrder(root);
printf("\n");
printf("中序遍历: ");
inOrder(root);
printf("\n");
printf("后序遍历: ");
postOrder(root);
printf("\n");
printf("层次遍历: ");
levelOrder(root);
printf("\n");
return 0;
}
Step2:点击编辑器左上角运行按钮直接运行,Terminal窗口可以看到打印内容。

树的高度及叶子节点数量:
具体代码操作如下:
Step1:复制以下代码,替换main.cpp文件中的代码。
#include <stdio.h>
#include <stdlib.h>
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");
exit(1);
}
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 if (data > root->data) {
root->right = insert(root->right, data);
}
return root;
}
// 计算树的高度
int height(TreeNode* root) {
if (root == NULL) {
return 0;
} else {
int leftHeight = height(root->left);
int rightHeight = height(root->right);
return (leftHeight > rightHeight) ? leftHeight + 1 : rightHeight + 1;
}
}
// 检查是否为叶子节点
bool isLeaf(TreeNode* node) {
return node != NULL && node->left == NULL && node->right == NULL;
}
// 计算叶子节点数量
int countLeaves(TreeNode* root) {
if (root == NULL) return 0;
if (isLeaf(root)) return 1;
return countLeaves(root->left) + countLeaves(root->right);
}
int main() {
TreeNode* root = NULL;
root = insert(root, 50);
root = insert(root, 30);
root = insert(root, 20);
root = insert(root, 40);
root = insert(root, 70);
root = insert(root, 60);
root = insert(root, 80);
printf("\n树的高度: %d\n", height(root));
printf("叶子节点数量: %d\n", countLeaves(root));
return 0;
}
Step2:点击编辑器左上角运行按钮直接运行,Terminal窗口可以看到打印内容。

查找节点:
具体代码操作如下:
Step1:复制以下代码,替换main.cpp文件中的代码。
#include <stdio.h>
#include <stdlib.h>
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");
exit(1);
}
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 if (data > root->data) {
root->right = insert(root->right, data);
}
return root;
}
// 查找节点
TreeNode* search(TreeNode* root, int data) {
if (root == NULL || root->data == data) {
return root;
}
if (data < root->data) {
return search(root->left, data);
} else {
return search(root->right, data);
}
}
int main() {
TreeNode* root = NULL;
root = insert(root, 50);
root = insert(root, 30);
root = insert(root, 20);
root = insert(root, 40);
root = insert(root, 70);
root = insert(root, 60);
root = insert(root, 80);
printf("\n查找节点:\n");
int searchValue = 40;
TreeNode* found = search(root, searchValue);
if (found != NULL) {
printf("找到节点 %d\n", searchValue);
} else {
printf("未找到节点 %d\n", searchValue);
}
return 0;
}
Step2:点击编辑器左上角运行按钮直接运行,Terminal窗口可以看到打印内容。

删除节点:
具体代码操作如下:
Step1:复制以下代码,替换main.cpp文件中的代码。
#include <stdio.h>
#include <stdlib.h>
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");
exit(1);
}
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 if (data > root->data) {
root->right = insert(root->right, data);
}
return root;
}
// 找到最小值节点
TreeNode* minValueNode(TreeNode* node) {
TreeNode* current = node;
while (current && current->left != NULL) {
current = current->left;
}
return current;
}
// 删除节点
TreeNode* deleteNode(TreeNode* root, int data) {
if (root == NULL) return root;
if (data < root->data) {
root->left = deleteNode(root->left, data);
} else if (data > root->data) {
root->right = deleteNode(root->right, data);
} else {
// 节点有一个或没有子节点
if (root->left == NULL) {
TreeNode* temp = root->right;
free(root);
return temp;
} else if (root->right == NULL) {
TreeNode* temp = root->left;
free(root);
return temp;
}
// 节点有两个子节点:获取右子树的最小节点
TreeNode* temp = minValueNode(root->right);
// 复制数据
root->data = temp->data;
// 删除右子树的最小节点
root->right = deleteNode(root->right, temp->data);
}
return root;
}
// 中序遍历
void inOrder(TreeNode* root) {
if (root != NULL) {
inOrder(root->left);
printf("%d ", root->data);
inOrder(root->right);
}
}
// 释放树的内存
void freeTree(TreeNode* root) {
if (root != NULL) {
freeTree(root->left);
freeTree(root->right);
free(root);
}
}
int main() {
TreeNode* root = NULL;
root = insert(root, 50);
root = insert(root, 30);
root = insert(root, 20);
root = insert(root, 40);
root = insert(root, 70);
root = insert(root, 60);
root = insert(root, 80);
printf("\n删除节点 20 (叶子节点)\n");
root = deleteNode(root, 20);
printf("中序遍历结果: ");
inOrder(root);
printf("\n");
printf("\n删除节点 30 (有一个子节点)\n");
root = deleteNode(root, 30);
printf("中序遍历结果: ");
inOrder(root);
printf("\n");
printf("\n删除节点 50 (有两个子节点)\n");
root = deleteNode(root, 50);
printf("中序遍历结果: ");
inOrder(root);
printf("\n");
// 释放树的内存
freeTree(root);
return 0;
}
Step2:点击编辑器左上角运行按钮直接运行,Terminal窗口可以看到打印内容。

4 综合案例:文件系统模拟
实现一个简单的文件系统模拟,使用树结构来表示目录和文件关系。
4.1 核心功能
- 创建根目录:
// 创建根目录
FileSystemNode* root = createDirectory("root");
- 创建子目录和文件:
// 创建新文件
FileSystemNode* createFile(const char* name, int size, const char* content) {
FileSystemNode* newNode = (FileSystemNode*)malloc(sizeof(FileSystemNode));
strncpy(newNode->name, name, MAX_NAME_LENGTH);
newNode->type = FILE_TYPE;
newNode->data.file.size = size;
strncpy(newNode->data.file.content, content, sizeof(newNode->data.file.content));
newNode->parent = NULL;
return newNode;
}
// 创建新目录
FileSystemNode* createDirectory(const char* name) {
FileSystemNode* newNode = (FileSystemNode*)malloc(sizeof(FileSystemNode));
strncpy(newNode->name, name, MAX_NAME_LENGTH);
newNode->type = DIRECTORY_TYPE;
newNode->data.directory.childCount = 0;
newNode->parent = NULL;
return newNode;
}
- 构建文件系统结构:
// 添加子节点到目录
bool addChild(FileSystemNode* parent, FileSystemNode* child) {
if (parent == NULL || child == NULL || parent->type != DIRECTORY_TYPE) {
return false;
}
if (parent->data.directory.childCount >= 10) {
printf("目录已满,无法添加更多子节点\n");
return false;
}
parent->data.directory.children[parent->data.directory.childCount++] = child;
child->parent = parent;
return true;
}
- 打印文件系统结构:
// 打印文件系统结构
void printFileSystem(FileSystemNode* node, int level) {
if (node == NULL) return;
for (int i = 0; i < level; i++) {
printf(" ");
}
if (node->type == FILE_TYPE) {
printf("- %s (文件, 大小: %d)\n", node->name, node->data.file.size);
} else {
printf("- %s (目录)\n", node->name);
for (int i = 0; i < node->data.directory.childCount; i++) {
printFileSystem(node->data.directory.children[i], level + 1);
}
}
}
- 查找文件:
// 查找节点
FileSystemNode* findNode(FileSystemNode* current, const char* name) {
if (current == NULL) return NULL;
if (strcmp(current->name, name) == 0) {
return current;
}
if (current->type == DIRECTORY_TYPE) {
for (int i = 0; i < current->data.directory.childCount; i++) {
FileSystemNode* found = findNode(current->data.directory.children[i], name);
if (found != NULL) {
return found;
}
}
}
return NULL;
}
- 释放内存:
// 释放文件系统内存
void freeFileSystem(FileSystemNode* root) {
if (root == NULL) return;
if (root->type == DIRECTORY_TYPE) {
for (int i = 0; i < root->data.directory.childCount; i++) {
freeFileSystem(root->data.directory.children[i]);
}
}
free(root);
}
4.2 完整代码实现及验证
Step1:复制以下代码,替换main.cpp文件中的代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_NAME_LENGTH 50
typedef enum { FILE_TYPE, DIRECTORY_TYPE } NodeType;
typedef struct FileSystemNode {
char name[MAX_NAME_LENGTH];
NodeType type;
union {
struct {
int size;
char content[1024];
} file;
struct {
int childCount;
struct FileSystemNode* children[10]; // 简化,假设最多10个子节点
} directory;
} data;
struct FileSystemNode* parent;
} FileSystemNode;
// 创建新文件
FileSystemNode* createFile(const char* name, int size, const char* content) {
FileSystemNode* newNode = (FileSystemNode*)malloc(sizeof(FileSystemNode));
strncpy(newNode->name, name, MAX_NAME_LENGTH);
newNode->type = FILE_TYPE;
newNode->data.file.size = size;
strncpy(newNode->data.file.content, content, sizeof(newNode->data.file.content));
newNode->parent = NULL;
return newNode;
}
// 创建新目录
FileSystemNode* createDirectory(const char* name) {
FileSystemNode* newNode = (FileSystemNode*)malloc(sizeof(FileSystemNode));
strncpy(newNode->name, name, MAX_NAME_LENGTH);
newNode->type = DIRECTORY_TYPE;
newNode->data.directory.childCount = 0;
newNode->parent = NULL;
return newNode;
}
// 添加子节点到目录
bool addChild(FileSystemNode* parent, FileSystemNode* child) {
if (parent == NULL || child == NULL || parent->type != DIRECTORY_TYPE) {
return false;
}
if (parent->data.directory.childCount >= 10) {
printf("目录已满,无法添加更多子节点\n");
return false;
}
parent->data.directory.children[parent->data.directory.childCount++] = child;
child->parent = parent;
return true;
}
// 打印文件系统结构
void printFileSystem(FileSystemNode* node, int level) {
if (node == NULL) return;
for (int i = 0; i < level; i++) {
printf(" ");
}
if (node->type == FILE_TYPE) {
printf("- %s (文件, 大小: %d)\n", node->name, node->data.file.size);
} else {
printf("- %s (目录)\n", node->name);
for (int i = 0; i < node->data.directory.childCount; i++) {
printFileSystem(node->data.directory.children[i], level + 1);
}
}
}
// 查找节点
FileSystemNode* findNode(FileSystemNode* current, const char* name) {
if (current == NULL) return NULL;
if (strcmp(current->name, name) == 0) {
return current;
}
if (current->type == DIRECTORY_TYPE) {
for (int i = 0; i < current->data.directory.childCount; i++) {
FileSystemNode* found = findNode(current->data.directory.children[i], name);
if (found != NULL) {
return found;
}
}
}
return NULL;
}
// 释放文件系统内存
void freeFileSystem(FileSystemNode* root) {
if (root == NULL) return;
if (root->type == DIRECTORY_TYPE) {
for (int i = 0; i < root->data.directory.childCount; i++) {
freeFileSystem(root->data.directory.children[i]);
}
}
free(root);
}
int main() {
// 创建根目录
FileSystemNode* root = createDirectory("root");
// 创建子目录和文件
FileSystemNode* docs = createDirectory("文档");
FileSystemNode* pics = createDirectory("图片");
FileSystemNode* file1 = createFile("readme.txt", 1024, "这是一个示例文件");
FileSystemNode* file2 = createFile("notes.txt", 2048, "一些笔记内容");
FileSystemNode* image1 = createFile("vacation.jpg", 4096, "JPEG图像数据");
// 构建文件系统结构
addChild(root, docs);
addChild(root, pics);
addChild(docs, file1);
addChild(docs, file2);
addChild(pics, image1);
// 打印文件系统结构
printf("文件系统结构:\n");
printFileSystem(root, 0);
// 查找文件
printf("\n查找文件:\n");
FileSystemNode* found = findNode(root, "notes.txt");
if (found != NULL && found->type == FILE_TYPE) {
printf("找到文件: %s, 内容: %s\n", found->name, found->data.file.content);
} else {
printf("未找到文件\n");
}
// 释放内存
freeFileSystem(root);
return 0;
}
Step2:点击编辑器左上角运行按钮直接运行,Terminal窗口可以看到打印内容。

至此,树&二叉树:数据的"分型宇宙"与"二分王国"的案例已全部完成。
6万+

被折叠的 条评论
为什么被折叠?



