树
- 树是一种数据结构
- 树的结构是非线性存储的, 存储具有一对多关系的数据集合
- 学习某种数据结构的时候,首先就需要学习它的基本概念和存储方式
基本概念
注意 : 树中的关系是一对多,不能多对一
结点 :树结构存储的每一个数据元素
根结点 :树中没有前驱的结点,通常一棵树只有一个结点
父结点(双亲结点), 子结点,兄弟结点
-
概念参考高中生物遗传系谱图
-
在一个具有链接关系的结点中
上层是父节点,下层是子结点, 同一个双亲的结点是兄弟结点 -
父结点,子结点和兄弟结点是相对而言的
叶子结点 :没有任何子结点的结点
结点的度 :结点具有的子树的个数
树的度 :各个结点中度的最大值
树的深度或高度:结点的层次从根结点起,根为第一层,根结点的孩子为第二层,依次类推.
注意:(作者观点)
深度和高度没必要区分,甚至定义也不必做严格要求
概念的区分对于写代码并没有太大的帮助
只要能把树的结构用代码表示出来, 写代码时如何定义都是对的
图示
图中
- A是根结点
- B和C为兄弟结点(同一个父亲)
- B和C是A的子结点, A是B和C的父结点
- **注意 : **
存储方式
树中数据是一对多的关系,所以肯定要有指针表示指向关系
我们通常使用链表来处理,但有一些结构使用数组也是可以的
双亲表示法
每个结点都指向它的父亲
分析结点
-
结点需要存储数据(数据域)
-
结点需要指向父亲(指针域)
-
根节点的指针域为空
#include <stdio.h>
#include <stdlib.h>
//树的双亲表示法
//结点的结构体
typedef struct TreeNode {
int data; //数据域,存放数据
int parent; //指针域,指向父亲
}Node;
Node *node[20]; //<<存放结点的数组,也就是我们的树结构>>
int now_node_size = 0;//当前结点的个数
int max_node_size = 0;//最大可存储的的结点个数
//初始化树结构
void InitTree() {
max_node_size = 20;//最大可存储的的结点个数与数组大小相同
now_node_size = 0; //当前结点的个数
}
//查询数组中是否有父节点
int FindParent(int parent_node) {
for (int i = 0; i < now_node_size; ++i) {
if (parent_node == node[i]->data) return i;
}
return -1;//若没有此父节点,返回-1;
}
//添加根结点
//int kye 根结点的数据
void InsertRoot(int key) {
Node* new_node = (Node*) malloc(sizeof(Node));
new_node->data = key; //存储数据
new_node->parent = -1; //根节点的指针域为空,用-1表示
node[now_node_size] = new_node;//将根节点添加到树结构中
now_node_size++; //插入成功, 更新当前结点的个数
}
//添加孩子结点到树中
//int key待添加的数据
//int parent_node 待添加结点的父亲的值
void InsertChild(int key, int parent_node) {
//判断树(数组)是否满了
if (now_node_size == max_node_size) {
//数组已满,插入失败
printf("数组已满,插入失败\n");
}
//数组未满,开始插入孩子结点
else {
//先找到父节点
int parent_index = FindParent(parent_node);
if (parent_index == -1) {
printf("没有此父节点,插入失败\n");
return;
}
else {
Node *new_node = (Node*)malloc(sizeof(Node));
new_node->data = key;
new_node->parent = parent_index;
node[now_node_size] = new_node;
now_node_size++; //更新数组(树)中结点个数
printf("子结点%d 插入成功,其父节点下标是: %d", key, parent_index);
}
}
}