这里就不简单的说明什么是树了,直接跳过来说树如何去建立起来吧:
注意:这里主要讲的是二叉树的建立
1.二叉树的建立:
在讲二叉树之前我们来说一下对于不同的二叉树,我们的存储的方式是什么?
树有两种结构,满二叉树和完全二叉树两种结构:
满二叉树定义:
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
完全二叉树定义:
完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。
首先我们第一个想到的一定是顺序存储的方式存储数据,但是这一定适应所有的二叉树存储么?
对于满二叉树和非完全二叉树的结构,我们可以采用顺序存储的结构方式(就是数组的方式去存储数据):
注意:这里图中我们可以看到对于完全二叉树和满二叉树这种结构,我们可以直接用顺序存储的方式去存储数据,而且不浪费资源,但是我们在现实中并不是一定遇到这样完美的二叉树,我们一般还是遇到的是非完全的二叉树结构,看图我们知道,用顺序存储的结构方式导致了极大的资源的浪费,空间利用率是非常低的,所以但对于非完全的二叉树我们都采用链表的数据结构方式去存储数据
所以我们今天直接讲的是非完全二叉树的建立,当然完全的二叉树一样可以通过数据结构链表去建立:
二叉树的节点结构类型:
一般我们采用的是二叉脸链表的结构方式:(节点的代码定义)
//学生信息的结构体
struct score_st{
int id;
char name[NAMESIZE];
int math;
int chinese;
};
//数据结构的结构体
struct node_st {
struct score_st data;
struct node_st *l;
struct node_st *r;
};
这里对于二叉树节点的定义,定义了一个学生结构体节点,里面有数据的结构关系,左子树和右子树两种结构,结构体节点里面还有学生信息的结构。
我们知道对于树的产生,包含了很多节点串在一起形成了树的结构,那么如何将树结构都连在一起的呢?这里就产生了树的建立的过程了:
//数据数组
int arr[]={1,3,6,4,8,9,34,76,54,32,11};
//创建数据节点
struct node_st *tree=NULL;//创建树节点
struct score_st temp,*find_temp;
//循环建立二叉树
for(int i=0;i<sizeof(arr)/sizeof(*arr);i++)
{
//节点的插入
temp.id=arr[i];
temp.math=rand()%100;
temp.chinese=rand()%100;
snprintf(temp.name,NAMESIZE,"stu:%d",arr[i]);//数据插入
insert(&tree,&temp);//数据节点插入的函数
}
int insert(struct node_st **root,struct score_st *data)//二级指针数据闯进去
{
// 创建数据节点
struct node_st *node ;
//递归的结束条件
if(*root==NULL)
{
//开辟节点空间
node =malloc(sizeof(struct node_st));
if(node==NULL)
{
return -1;
}
node->data=*data;//初始化节点,否则空指针出现导致意外的结果发生
node->l=NULL;
node->r=NULL;
*root =node ;//找到空位就将数据插进去
return 0;
}
//遍历二叉树
if(data->id<(*root)->data.id)
{
return insert(&(*root)->l,data);//递归调用法
}
else
{
return insert(&(*root)->r,data);
}
}
由上面的代码我们可以知道,我们创建了树的节点,然后创建了学生信息的结构体,然后在循环中对学生信息结构体填充,然后插入树中去,在insert函数中,我们运用了递归的思想(这里如果对递归的思想不清楚可以去了解一下递归的思想再过来),递归有终止条件,当终止条件产生的时候,就找到了空的位置,就会开辟节点,为节点开辟空间,然后结构体数据填充,依次循环下去就把树建立好了!
2.(二叉树的搜索)验证树建立的正确性:
struct score_st *find(struct node_st *root,int id)
{
if(root==NULL)
{
return NULL;
}
if(id==root->data.id)
return &root->data;
if(id<root->data.id)
return find(root->l,id);//递归查找到方法
if(id>root->data.id)
return find(root->r,id);//递归查找到方法
}
这里还是用了递归的搜索的方式,直到找到了自己想找的树节点,然后返回回去,如果没找到树,就说明树没有这个数据节点;
3.将树的形状打印出来:
void draw_(struct node_st *root,int level)
{
//递归的结束标志
if(root==NULL)
{
return;
}
draw_(root->l,level+1);
for(int i=0;i<level;i++)
{
printf(" ");
}
printf("%s,%d,%d,%d\n",root->data.name,root->data.chinese,root->data.name,root->data.id);
draw_(root->r,level+1);
}
void draw(struct node_st *root)
{
draw_(root,0);
}
这里将树的形状打印出来的方式,还是通过递归搜索的方式;
注意:
这里将树右转动一下的方式将树的形状打印出来;
打印出来的代码结果:
stu:1,86,18690068,1
stu:3,15,18690132,3
stu:4,92,18690260,4
stu:6,35,18690196,6
stu:8,21,18690324,8
stu:9,27,18690388,9
stu:11,68,18690708,11
stu:32,36,18690644,32
stu:34,59,18690452,34
stu:54,26,18690580,54
stu:76,26,18690516,76
总代码参考:
#include <stdio.h>
#include <stdlib.h>
#define NAMESIZE 20
struct score_st{
int id;
char name[NAMESIZE];
int math;
int chinese;
};
struct node_st {
//socre
struct score_st data;
struct node_st *l;
struct node_st *r;
};
int insert(struct node_st **root,struct score_st *data)
{
struct node_st *node ;
if(*root==NULL)
{
node =malloc(sizeof(struct node_st));
if(node==NULL)
{
return -1;
}
node->data=*data;
node->l=NULL;
node->r=NULL;
*root =node ;
return 0;
}
if(data->id<(*root)->data.id)
{
return insert(&(*root)->l,data);
}
else
{
return insert(&(*root)->r,data);
}
}
struct score_st *find(struct node_st *root,int id)
{
if(root==NULL)
{
return NULL;
}
if(id==root->data.id)
return &root->data;
if(id<root->data.id)
return find(root->l,id);
if(id>root->data.id)
return find(root->r,id);
}
void draw_(struct node_st *root,int level)
{
if(root==NULL)
{
return;
}
draw_(root->l,level+1);
for(int i=0;i<level;i++)
{
printf(" ");
}
printf("%s,%d,%d,%d\n",root->data.name,root->data.chinese,root->data.name,root->data.id);
draw_(root->r,level+1);
}
void draw(struct node_st *root)
{
draw_(root,0);
}
int main()
{
int arr[]={1,3,6,4,8,9,34,76,54,32,11};
struct node_st *tree=NULL;
struct score_st temp,*find_temp;
for(int i=0;i<sizeof(arr)/sizeof(*arr);i++)
{
temp.id=arr[i];
temp.math=rand()%100;
temp.chinese=rand()%100;
snprintf(temp.name,NAMESIZE,"stu:%d",arr[i]);
insert(&tree,&temp);//shujucharu
}
#if 0
int find_id=3;
find_temp=find(tree,find_id);
if(find_temp==NULL)
{
printf("Can not find!\n");
}
else
{
printf("%s,%d,%d,%d\n",find_temp->name,find_temp->chinese,find_temp->name,find_temp->id);
}
#endif
draw(tree);
exit(0);
}
总结一下:
该文对于数据结构树的如何产生和数据打印和搜索,以及将树的形状进行打印出来,树的应用还是非常广泛的,比如数据库,文件系统,编程语言等......,这里也是简单介绍了一下数据结构树的建立和搜索,期待大家更深的探索!