树
-
树是一种一对多的数据结构,这个一对多很好解释,就比如一只狗妈妈,会有多只小奶狗,这不就有一对多的意思吗!
-
树的根节点有且只有一个,就比如小奶狗们只有一个亲狗妈。
-
那么图上的 B C D E 都是树的根节点 A 的孩子; 总之,树就是有很多结点构成,只不过这些结点在树中会有不同的称呼,来分析一下下图
-
度----结点拥有的子树数称为结点的度, 度为 0 的结点称为树的叶结点;树的度是树内结点的度的最大值;此树的度为 3 。
-
树中结点之间的关系都是表达在字面上的,比如 B 是 A 的左孩子, C 是 A 的有孩子,A 是它们的双亲, 接下来的以此类推, 这关系还有堂兄弟关系、祖宗关系等。
-
树的深度(高度)就是树中结点的最大层次,比如上图中根结点 A 为第一层, 根的孩子们为第二层,以此类推,此树的深度为 5 。
-
有许多的集合在一起就可以形成森林。
树的存储结构
存储结构基本上就是顺序存储和链式存储这两种,然而对于树这种一对多的结构,用这两种存储结构更便利,产生主要的三种存储结构表示法:双亲表示法、孩子表示法、孩子兄弟表示法。
1. 双亲表示法
其实双亲表示法内部主要还是以顺序存储为主
先来看看该表示法的图吧(来源于《大话数据结构》)
特点:
- 根结点是没有双亲,根结点的位置位置域为-1
- 根据结点的parent指针很容易找到它的双亲结点。所用时间复杂度为O(1),直到parent为-1时,表示找到了树结点的根。
- 找到孩子结点,需要遍历整个结构。
代码
#include <stdio.h>
#define MAX_TREE_SIZE 100
typedef char ElemType;
typedef struct PTNode
{
ElemType data;
int parent;
}PTNode;
typedef struct
{
PTNode nodes[MAX_TREE_SIZE];
int n; //This is number of the node
}PTree;
void creat_PNode(PTree *tree)
{
char c;
int index;
printf("Please enter the numbers of node: ");
scanf("%d", &(tree->n));
printf("Please enter value of the node, and the positon of parent nodes in the array: \n");
for(int i = 0; i < tree->n; i++)
{
getchar();
scanf("%c %d", &c, &index);
tree->nodes[i].data = c;
tree->nodes[i].parent = index;
}
}
void find_Parent(PTree tree)
{
char c;
int flag = 0;
printf("Please enter vlaue of node to be finded: ");
getchar();
scanf("%c", &c);
for (int i = 0; i < tree.n; i++)
{
if (tree.nodes[i].data == c)
{
flag = 1;
int parent_Int = tree.nodes[i].parent;
printf("%c of parent node is %c , the parent node`s location subscript is %d", c, tree.nodes[parent_Int].data, parent_Int);
}
}
if (flag == 0)
{
printf("It has not the node about %c in the tree!\n", c);
}
}
int main()
{
PTree tree;
creat_PNode(&tree);
find_Parent(tree);
return 0;
}
2.孩子兄弟表示法
定义:把每个结点的孩子结点排列起来,以单链表作为存储结构,则n个结点有n个孩子链表,如果是叶子结点则此单链表为空。然后n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组中。
来个图吧
代码
#include <stdio.h>
#include <stdlib.h>
#define MAX_TREE_SIZE 100
typedef char ElemType;
typedef struct CTNode //child node
{
int child;
struct CTNode *next;
}*ChildPtr;
typedef struct //Head structure
{
ElemType data;
ChildPtr firstchild;
}CTHead;
typedef struct
{
CTHead node[MAX_TREE_SIZE];
int n; //The numbers of node
// int r; //The position of root of the tree The root node of the default tree is at the array node[0]
}CTree;
void creat_Tree(CTree *tree)
{
printf("Please enter the number of node: ");
scanf("%d", &(tree->n));
for (int i = 0; i < tree->n; i++)
{
printf("Please enter value of %dth node: ", i + 1);
getchar();
scanf("%c", &(tree->node[i].data));
tree->node[i].firstchild = (ChildPtr)malloc(sizeof(CTNode));
tree->node[i].firstchild->next = NULL;
printf("Please enter the number of child node of node \'%c\' :", tree->node[i].data);
int num = 0;
scanf("%d", &num);
if (num != 0)
{
ChildPtr p = tree->node[i].firstchild;
for (int j = 0; j < num; j++)
{
ChildPtr pNew = (ChildPtr)malloc(sizeof(CTNode));
pNew->next = NULL;
printf("Please enter the position of the %dth child node in the sequence table : ", j + 1);
scanf("%d", &(pNew->child));
p->next = pNew;
p = pNew;
}
}
}
}
void find_Tree(CTree tree)
{
char c;
int flag = 0;
printf("You need to find out which node`s child node : ");
getchar();
scanf("%c", &c);
for (int i = 0; i < tree.n; i++)
{
if (c == tree.node[i].data)
{
ChildPtr p = tree.node[i].firstchild->next;
while(p)
{
flag = 1;
printf("%c ", tree.node[p->child].data);
p = p->next;
}
printf("\n");
break;
}
}
if (flag == 0)
{
printf("%c node is leaf node\n", c);
}
}
int main()
{
CTree tree;
creat_Tree(&tree);
find_Tree(tree);
return 0;
}
3.孩子兄弟表示法
定义:任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟存在也是唯一的。因此,设置两个指针,分别指向该结点的第一个孩子和此结点的右兄弟。
结构定义:
#define MAX_TREE_SIZE 100
typedef int ElemeType;
typedef struct CSNode{
ElemeType data;
struct CSNode * firstchild; //存储该结点的第一个孩子的存储地址
struct CSNode * rightsib; //存储该结点的右兄弟结点的存储地址
}CSNode, *CSTree;