一、树(Tree)结构详解
1. 树的基本概念
树的核心特性
-
非线性结构:数据元素之间存在一对多的层次关系
-
递归定义:树的子树仍然是树
-
专业术语:
-
度(Degree):结点拥有的子树数
-
叶子结点:度为0的结点
-
层次(Level):根为第1层,依次递增
-
深度/高度:树中结点的最大层次
-
-
树的存储结构
c
/* 树结点的链式存储结构 */
typedef struct _tree_node_ {
DATATYPE data;
struct _tree_node_ *left; // 左子树指针
struct _tree_node_ *right; // 右子树指针
} TreeNode;

2. 二叉树专题
二叉树特殊形态
-
斜树:所有结点只有左子树或只有右子树
-
满二叉树:
-
所有分支结点都有左右子树
-
所有叶子在同一层
-
-
完全二叉树:
-
结点位置与同深度满二叉树对应
-
叶子结点集中在左部连续位置
-
二叉树性质(重要公式)
-
第i层最多有2^(i-1)个结点
-
深度为k的二叉树最多有2^k -1个结点
-
叶子结点数n0 = 度为2的结点数n2 + 1
-
具有n个结点的完全二叉树深度为⌊log₂n⌋+1
3. 二叉树遍历实现
(1) 先序遍历
c
void PreOrderTraverse(TreeNode *root) {
if (NULL == root) return;
printf("%c", root->data); // 访问根结点
PreOrderTraverse(root->left); // 遍历左子树
PreOrderTraverse(root->right); // 遍历右子树
}
(2) 中序遍历
c
void InOrderTraverse(TreeNode *root) {
if (NULL == root) return;
InOrderTraverse(root->left); // 遍历左子树
printf("%c", root->data); // 访问根结点
InOrderTraverse(root->right); // 遍历右子树
}
(3) 后序遍历
c
void PostOrderTraverse(TreeNode *root) {
if (NULL == root) return;
PostOrderTraverse(root->left); // 遍历左子树
PostOrderTraverse(root->right); // 遍历右子树
printf("%c", root->data); // 访问根结点
}
4. 二叉树创建与销毁
静态创建示例
c
char data[] = "abd#f###c#eg###"; // '#'表示空结点
int ind = 0;
void CreateTree(TreeNode **root) {
char c = data[ind++];
if ('#' == c) {
*root = NULL;
return;
}
*root = malloc(sizeof(TreeNode));
(*root)->data = c;
CreateTree(&(*root)->left); // 递归创建左子树
CreateTree(&(*root)->right); // 递归创建右子树
}
内存释放
c
void DestroyTree(TreeNode *root) {
if (NULL == root) return;
DestroyTree(root->left); // 释放左子树
DestroyTree(root->right); // 释放右子树
free(root); // 释放当前结点
}
二、哈希表(Hash Table)实现
1. 哈希表核心概念
关键技术点
-
哈希函数:将关键字映射到存储位置
-
冲突解决:
-
开放定址法:线性探测、二次探测
-
链地址法:数组+链表结构
-
常用哈希函数
c
/* 除留余数法 */
int HSFun(HSTable* hs, DATATYPE* data) {
return *data % hs->tlen; // 取模运算得到索引
}
2. 哈希表完整实现
结构定义
c
typedef struct {
DATATYPE* head; // 存储数组
int tlen; // 表长度
} HSTable;
创建与初始化
c
HSTable* CreateHsTable(int len) {
HSTable* hs = malloc(sizeof(HSTable));
hs->head = malloc(sizeof(DATATYPE) * len);
for (int i = 0; i < len; i++) {
hs->head[i] = -1; // -1表示空位置
}
hs->tlen = len;
return hs;
}
插入操作(线性探测法)
c
int HSInsert(HSTable* hs, DATATYPE* data) {
int ind = HSFun(hs, data);
while (hs->head[ind] != -1) { // 处理冲突
ind = (ind + 1) % hs->tlen; // 线性探测
}
hs->head[ind] = *data;
return 0;
}
查找实现
c
int HsSearch(HSTable* hs, DATATYPE* data) {
int ind = HSFun(hs, data);
int old_ind = ind;
while (hs->head[ind] != *data) {
ind = (ind + 1) % hs->tlen;
if (old_ind == ind) return -1; // 未找到
}
return ind; // 返回找到的索引
}
三、Linux内核链表解析
1. 内核链表特点

与传统链表的区别
-
嵌入设计:list_head结构体嵌入到宿主数据结构中
-
双向循环:首尾相连形成环状结构
-
高复用性:与具体数据类型解耦
核心结构定义
c
struct list_head {
struct list_head *next, *prev;
};
2. 内核链表操作示例
链表初始化
c
struct my_data {
int value;
struct list_head list; // 嵌入链表结点
};
INIT_LIST_HEAD(&my_list); // 初始化链表头
添加结点
c
list_add(&new_node->list, &head); // 头插法
list_add_tail(&new_node->list, &head); // 尾插法
遍历链表
c
struct my_data *pos;
list_for_each_entry(pos, &my_list, list) {
printk("Value: %d\n", pos->value);
}
删除结点
c
list_del(&node->list); // 从链表中移除
kfree(node); // 释放内存
四、嵌入式开发应用建议
-
树结构适用场景:
-
配置文件解析(XML/JSON)
-
设备树(Device Tree)管理
-
路由算法实现
-
-
哈希表优化技巧:
-
选择质数作为表长度减少冲突
-
动态扩容机制设计
-
嵌入式环境下可考虑静态内存分配
-
-
内核链表最佳实践:
-
多线程环境配合spinlock使用
-
使用container_of宏获取宿主结构
-
注意内存屏障(Memory Barrier)的使用
-