树型结构:
1.树的基本概念
一种表示层次关系(一对多)的数据结构
有且只有一个特定的特点,该节点没有前驱节点,被称为根节点
剩余的n个互不相交的子集,其中每个子集也都是一棵树,都被称为根节点的子树
注意:树型结构具有递归性(树中有树)
2.树的表示方式:
倒悬树、嵌套法、凹凸法
3.树的专业术语
节点:组成树的基础元素、同时它也是一棵树
节点的度:该节点子树的数量
树的度:树中所有节点的度的最大值
树的深度(高度):树的最大层次为树的深度
节点的层次:根节点的层次为1,它的孩子层次为2,孩子的孩子层次为3,以此类推
叶子节点:节点的度为0的节点
双亲节点和孩子节点:节点的子树被称为该节点的孩子节点,该节点就是孩子的双亲节点
兄弟节点:具有同一个双亲节点的节点互为兄弟节点
堂兄弟节点:双亲节点互为兄弟节点
祖先:从根节点出发到该节点,路径上经过的所有节点都被称为该节点的祖先
子孙:一个节点的子树中任意一个节点都是它的子孙
4.树的存储
树可以顺序存储、链式存储,还可以混合存储
可以根据存储的信息不同,树有以下存储方式
双亲表示法: 顺序
位置 data 双亲下标
0 A -1
1 B 0
2 C 0
3 D 1
4 E 1
5 F 1
6 G 2
7 H 4
优点:方便找到双亲
缺点:查找孩子结点麻烦
pppp
孩子表示法:
顺序: 浪费内存
位置 data son_arr(存储子节点的数量)
0 A 1,2,8
1 B 3,4,5
2 C 6
3 D
4 E 7
5 F
6 G
7 H
链式: 节约内存空间
位置 data ListHead(存储子节点的链表)
0 A 1->2->8->NULL
1 B 3->4->5->NULL
2 C 6->NULL
3 D NULL
4 E 7->NULL
5 F NULL
6 G NULL
7 H NULL
优点:查找孩子节点方便
缺点:找双亲不方便
兄弟表示法:
链式
双亲只存储第一个子节点 数据 链式指向所有兄弟节点
优点:可以方便找到所有的兄弟节点
缺点:找双亲麻烦
注意:普通树不常用 ,一般会使用二叉树进行存储
双亲表示法:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// 顺序存储 双亲表示法
typedef struct TreeNode
{
char data; // 数据
int parent; // 双亲节点下标
}TreeNode;
// 设计顺序结构存储一棵树
typedef struct Tree
{
TreeNode* arr; // 存储节点内存的首地址
size_t cal; // 容量
size_t cnt; // 数量
}Tree;
// 创建树
Tree* create_tree(size_t cal)
{
Tree* tree = malloc(sizeof(Tree));
tree->arr = malloc(sizeof(TreeNode)*cal);
tree->cal = cal;
tree->cnt = 0;
return tree;
}
// 添加结点 data要加入的数据 parent是双亲数据
bool add_tree(Tree* tree,char data,char parent)
{
// 树不存在满 可以扩容
if(tree->cnt >= tree->cal)
{
tree->cal *= 2;
tree->arr =
realloc(tree->arr,(tree->cal)*sizeof(TreeNode));
}
// 根节点没有双亲,约定它双亲为 '\0'
if('\0' == parent && 0 == tree->cnt)
{
tree->arr[0].data = data;
tree->arr[0].parent = -1;
tree->cnt++;
return true;
}
for(int i=0; i<tree->cnt; i++)
{
if(parent == tree->arr[i].data)
{
tree->arr[tree->cnt].data = data;
tree->arr[tree->cnt++].parent = i;
return true;
}
}
return false;
}
void show_tree(Tree* tree)
{
for(int i=0; i<tree->cnt; i++)
{
printf("index:%d data:%c parent:%d\n",
i,tree->arr[i].data,tree->arr[i].parent);
}
}
// 计算节点的度
int node_count(Tree* tree,char data)
{
int index = -1,count = 0;
for(int i=0; i<tree->cnt; i++)
{
if(data == tree->arr[i].data) index = i;
}
if(-1 == index) return -1;
for(int i=0; i<tree->cnt; i++)
{
if(index == tree->arr[i].parent) count++;
}
return count;
}
// 计算节点data的高度
int _high_tree(Tree* tree,char data)
{
int index = -1;
for(int i=0; i<tree->cnt; i++)
{
if(data == tree->arr[i].data)
{
index = i;
break;
}
}
if(-1 == index) return -1;
int son_high_max = 0;
for(int i=0; i<tree->cnt; i++)
{
if(index == tree->arr[i].parent)
{
int high = _high_tree(tree,tree->arr[i].data);
if(high > son_high_max) son_high_max = high;
}
}
return son_high_max + 1;
}
// 计算树的高度
int high_tree(Tree* tree)
{
return _high_tree(tree,tree->arr[0].data);
}
int main(int argc,const char* argv[])
{
Tree* tree = create_tree(10);
add_tree(tree,'A','\0');
add_tree(tree,'B','A');
add_tree(tree,'C','A');
add_tree(tree,'D','B');
add_tree(tree,'E','B');
add_tree(tree,'F','B');
add_tree(tree,'G','C');
add_tree(tree,'H','E');
add_tree(tree,'X','A');
add_tree(tree,'Y','H');
show_tree(tree);
printf("son_count=%d\n",node_count(tree,'C'));
printf("tree_high=%d\n",high_tree(tree));
}