二叉树及平衡二叉树 纯C语言实现
作者:cuicui
实现了二叉树节点的增加、查询、删除还有将二叉树变成平衡二叉树。
定义速览
- 深度(层数)、层、叶子、孩子、兄弟、堂兄弟。
- 二叉树:两个子节点,且区分左右节点。
- 满二叉树。
- 完全二叉树:最后两层可以出现子节点不为2的节点,如果只有一个子节点,必须为左节点。
- 平衡二叉树:对于所有节点,左树右树的节点数差一。
- 存储方式:顺序(数组)、链式。
- 遍历:按行、先序(根左右)、中序(左根右)、后序(左右根)。
- 特别的:已知先中或中后两种遍历方式可以重建整个树,先后不行。
代码中的函数定义
insert()//插入节点,默认的树生成方式是,大的数放右边,比根节点小的数放左边,依次比较。
paint()、show()//把树显示出来,为方便显示,这棵树是向左放倒的。
delete()//删除节点,删除一个节点后把它的右子树放上来,如果节点冲突,则把原节点的左子树放到新节点的最左边。
balance()//把普通二叉树变成平衡二叉树。
turnleft()//平衡时用到,把右节点放上来,原节点变为左节点。
turnright()//平衡时用到,把左节点放上来,原节点变成右节点。
源代码
用学生的ID排列做个例子 不想看代码的话就看看运行结果就行啦
#include "stdio.h"
#include "stdlib.h"
#define NAMESIZE 32
struct stu_st
{
int id;
char name[NAMESIZE];
int score;
};
struct node_st
{
struct stu_st stu;
struct node_st *l;
struct node_st *r;
};
struct node_st *tree = NULL;//全局变量
void printf_stu(struct stu_st *st)
{
printf("id:%d,name:%s,score:%d", st->id, st->name, st->score);
}
//插入
int insert(struct node_st **root, struct stu_st *data)
{
struct node_st *node;
//这一判断比较关键,根节点和叶子节点都走这里,没有就申请内存
if (*root == NULL)
{
node = malloc(sizeof(*node));
if (node == NULL)
return -1;
node->stu = *data;
node->l = NULL;
node->r = NULL;
*root = node;
return 0;
}
if ((*root)->stu.id >= (*data).id)
insert(&((*root)->l), data);
else
{
insert(&((*root)->r), data);
}
}
//查找学生
struct stu_st *find(struct node_st *node, int id)
{
if (node == NULL)
{
return NULL;
}
if ((*node).stu.id == id)
{
return &(node->stu);
}
if ((*node).stu.id < id)
{
return find(node->r, id);
}
else
{
return find(node->l, id);
}
}
//画右子树 画自己 画左子树
void paint(struct node_st *root, int level)
{
if (root == NULL)
return;
paint(root->r, level + 1);
int i = 0;
for (i = 0; i < level; i++)
{
printf(" ");
}
printf("%d\n", root->stu.id);
paint(root->l, level + 1);
}
//显示树
void show(struct node_st *root)
{
printf("===================================\n");
paint(root, 0);
}
//获得节点总数
int get_node_sum(struct node_st *node)
{
if (node == NULL)
return 0;
else
return (get_node_sum(node->l) + 1 + get_node_sum(node->r));
}
//获得最左节点
struct node_st *get_min(struct node_st *root)
{
if (root->l == NULL)
return root;
return get_min(root->l);
}
//获得最右节点
struct node_st *get_max(struct node_st *root)
{
if (root->r == NULL)
return root;
return get_max(root->r);
}
//平衡树时,树向左转
void turnleft(struct node_st **root)
{
struct node_st *node = *root;
*root = node->r;
node->r = NULL;
get_min(*root)->l = node;
show(tree);
}
//平衡树时,树向右转
void turnright(struct node_st **root)
{
struct node_st *node = *root;
*root = node->l;
node->l = NULL;
get_max(*root)->r = node;
show(tree);
}
//把普通二叉树变成平衡二叉树
void balance(struct node_st **node)
{
int sub;
if (*node == NULL)
return;
while (1)
{
sub = get_node_sum((*node)->r) - get_node_sum((*node)->l);
if(sub>=-1 && sub<=1)
break;
if (sub > 1)
turnleft(node);
else if (sub < -1)
{
turnright(node);
}
}
balance(&(*node)->l);
balance(&(*node)->r);
}
//删除一个节点把它的右子树放上来
void delete(struct node_st **root, int id)
{
struct node_st **node = root;
struct node_st *cur = NULL;
while (*node !=NULL && (*node)->stu.id != id)
{
if(id < (*node)->stu.id)
node = &(*node)->l;
else
{
node = &(*node)->r;
}
}
if(*node == NULL)
return ;
cur = *node;
if(cur->r == NULL)
*node = cur->l;
else
{
*node = cur->r;
get_min(*node)->l = cur->l;
}
free(cur);
}
int main()
{
int i;
struct stu_st temp, *stu_p;
int arr[] = {1, 2, 3, 9, 8, 4, 5};
for (i = 0; i < sizeof(arr) / sizeof(*arr); i++)
{
temp.id = arr[i];
snprintf(temp.name, NAMESIZE, "stu%d", arr[i]);
temp.score = rand() % 100;
insert(&tree, &temp);
}
show(tree);//把生成的树显示一下
balance(&tree);
//show(tree);
int deleteID = 4;
delete(&tree,deleteID);
show(tree);
return 0;
}
运行结果
树是向左倒的哦
==================================生成好的树
9
8
5
4
3
2
1
===================================树向左转
9
8
5
4
3
2
1
===================================树向左转
9
8
5
4
3
2
1
===================================树向左转
9
8
5
4
3
2
1
===================================树向右转后
9
8
5
4
3
2
1
===================================树向右转
9
8
5
4
3
2
1
===================================子树向右转
9
8
5
4
3
2
1
===================================子树向左转,大功告成
9
8
5
4
3
2
1
===================================删掉一个节点,把右子树放上来
9
8
5
3
2
1