众所周知,二叉树在数据结构领域属于一个较难的课题,本文针对二叉树的基本操作逻辑,实现了一个基于二叉树的学生成绩管理系统,包含初始化增加删除打印等各大基本功能,和大家一起分享,小编也是个初学者,有什么不正确的地方望指正。
本代码用了大量的递归函数,小白慎进,毕竟这是个很掉头发的东西,可真让人头秃!!!
本代码实现五大功能,分别是:
1、添加学生编号、姓名和成绩,将数据插入二叉树中
2、输入编号,找到相应的二叉树节点,可查询学生成绩信息
3、打印出二叉树所有节点的信息
4、按编号删除相应的节点
5、退出系统
代码300多行少是少了点,就是一个比较简单的系统,我觉得对于数据结构的初学者来说应该还是有点帮助的,我敲了一上午,头发怕是掉了不少,难受呀!!!
定义一个记录学生成绩的结构体和一个二叉树结构体
struct stu_grade
{
char stu_name[30];//姓名
int grade;//成绩
int number;//编号(学号)
};
//定义一个二叉树的结构体
typedef struct student_list
{
struct student_list *lchild;//左孩子
struct student_list *rchild;//右孩子
int height;
struct stu_grade perfor_info;//学生结构体类型的数据
}student_node;
申请一个二叉树根节点,并分配内存初始化它
//初始化二叉树
student_node *request_student_node(const struct stu_grade *value)
{
student_node *new_node;
new_node = malloc(sizeof(student_node));
if (new_node == NULL)
{
perror("没有申请到二叉树节点\n");
return NULL;
}
if (value != NULL)
{
new_node->perfor_info = *value;
new_node->lchild = NULL;
new_node->rchild = NULL;
}
return new_node;
}
解决树不平衡的问题,也就是实现二叉树自平衡
//记录节点的高度
#define MAX(A, B) ((A)>(B)?(A):(B))
int get_tree_height(student_node *root)
{
if(root == NULL)
return 0;
return MAX(get_tree_height(root->lchild), get_tree_height(root->rchild))+1;
}
//解决左左不平衡
student_node *tree_node_rotate_right(student_node *root)
{
student_node *tmp;
tmp = root->lchild;
root->lchild = tmp->rchild;
tmp->rchild = root;
tmp->height = get_tree_height(tmp);
root->height = get_tree_height(root);
return tmp;//返回新的root的地址给调用这个函数的人,用于更新新的root地址
}
//解决右右不平衡
student_node *tree_node_rotate_left(student_node *root)
{
student_node *tmp;
tmp = root->rchild;
root->rchild = tmp->lchild;
tmp->lchild = root;
tmp->height = get_tree_height(tmp);
root->height = get_tree_height(root);
return tmp;
}
//解决左右不平衡
student_node *tree_node_rotate_left_right(student_node *root)
{
root->lchild = tree_node_rotate_left(root->lchild);
root = tree_node_rotate_right(root);
return root;
}
//解决右左不平衡
student_node *tree_node_rotate_right_left(student_node *root)
{
root->rchild = tree_node_rotate_right(root->rchild);
root = tree_node_rotate_left(root);
return root;
}
往二叉树里插入数据,增加学生成绩信息
//增加插入学生成绩数据
student_node *insert_node_to_tree(student_node *root,student_node *new_node)
{
if (root == NULL)
return new_node;
if(root ->perfor_info.number > new_node->perfor_info.number)
{
root->lchild = insert_node_to_tree(root->lchild,new_node);
}
else
{
root->rchild = insert_node_to_tree(root->rchild,new_node);
}
if(get_tree_height(root->lchild)-get_tree_height(root->rchild) == 2)//左不平衡
{
//如果插入的数据比跟的左树节点的数据要小,那他肯定是插入到root->lchild的左边去,出现了左左不平衡
if(new_node->perfor_info.number < root->lchild->perfor_info.number)//左左不平衡
{
root = tree_node_rotate_right(root);
}
else//否则则是插入到root->lchild的右边去,出现了左右不平衡
{
root = tree_node_rotate_left_right(root);
}
}
else if(get_tree_height(root->rchild)-get_tree_height(root->lchild) == 2)//右不平衡
{
if( new_node->perfor_info.number >= root->rchild->perfor_info.number)//右右不平衡
{
printf("出现右不平衡\n");
root = tree_node_rotate_left(root);
}
else//右左不平衡
{
root = tree_node_rotate_right_left(root);
}
}
root->height = get_tree_height(root);
return root;
}
按编号查询学生信息
//搜索查询学生信息
student_node *find_tree_node(student_node *root,int input_value)
{
if (root == NULL)
return NULL;
if (root->perfor_info.number > input_value)
{
return find_tree_node(root ->lchild,input_value);
}
else if (root->perfor_info.number < input_value)
{
return find_tree_node(root ->rchild,input_value);
}
return root;
}
打印所有学生的成绩信息
//打印所有学生的信息(中序遍历打印)
void tree_for_each(student_node *root)
{
if (root == NULL)
{
return;
}
tree_for_each(root->lchild);
printf("编号:%d,学生姓名:%s,学生成绩:%d\n",root->perfor_info.number,root->perfor_info.stu_name,root->perfor_info.grade);
tree_for_each(root->rchild);
}
按编号删除学生信息
//删除学生成绩信息
student_node *remove_tree_node(student_node *root, int rm_value)
{
student_node *tmp;
if(root == NULL)//如果树为NULL则直接返回
return NULL;
if(root->perfor_info.number == rm_value)
{
if(root->lchild==NULL && root->rchild == NULL)
{
free(root);
return NULL;
}
else if(root->lchild != NULL)//如果有左子树
{
for(tmp=root->lchild; tmp->rchild != NULL; tmp=tmp->rchild);//用tmp来记录root的左子树当中的最右边的节点(也就是左树当中的最大值)
root->perfor_info.number = tmp->perfor_info.number;//将左子树中的最大值赋值到我们要删除的节点上(等同于覆盖了这个节点)
root->lchild = remove_tree_node(root->lchild, tmp->perfor_info.number);//递归的删除掉重复出来的这个节点,将左子树的数据更新进来
}
else//如果只有右子树
{
for(tmp=root->rchild; tmp->lchild != NULL; tmp=tmp->lchild);//用tcmp来记录root的右子树中的最左边的节点(也就是有树当中的最小值)
root->perfor_info.number = tmp->perfor_info.number;//将右子树中的最小值赋值到我们要删除的节点上(等同于覆盖了这个节点)
root->rchild = remove_tree_node(root->rchild, tmp->perfor_info.number);//递归的删除掉重复出来的这个节点,将右子树的数据更新进来
}
}
else if(rm_value < root->perfor_info.number)//如果删除的数据比这个节点要小,则继续往左边去删除节点
{
root->lchild = remove_tree_node(root->lchild, rm_value);
}
else//如果删除的数据比这个节点要大,则继续往右边去删除
{
root->rchild = remove_tree_node(root->rchild, rm_value);
}
//插入新节点结束后再判断是否出现不平衡
if(get_tree_height(root->lchild)-get_tree_height(root->rchild) == 2)//左不平衡
{
//如果插入的数据比跟的左树节点的数据要小,那他肯定是插入到root->lchild的左边去,出现了左左不平衡
if( get_tree_height(root->lchild->lchild)-get_tree_height(root->lchild->rchild) == 1)//左左不平衡
{
root = tree_node_rotate_right(root);
}
else//否则则是插入到root->lchild的右边去,出现了左右不平衡
{
root = tree_node_rotate_left_right(root);
}
}
else if(get_tree_height(root->rchild)-get_tree_height(root->lchild) == 2)//右不平衡
{
if( get_tree_height(root->rchild->rchild)-get_tree_height(root->rchild->lchild) == 1)//右右不平衡
{
root = tree_node_rotate_left(root);
}
else//右左不平衡
{
root = tree_node_rotate_right_left(root);
}
}
root->height = get_tree_height(root);
return root;//如果当前root这个节点不是我们删除的节点,我们便原封不动的返回出去
}
主函数
int main(void)
{
int choose,input_value;
struct stu_grade input_student_data;//定义一个学生结构体类型的数据用来缓存学生数据
student_node *root = NULL,*new_node,*find_node;
//初始化一个节点root为空
while(1)
{
printf("****************欢迎来到学生成绩管理系统************\n");
printf("请输入数字选择相应的指令\n");
printf("1、增加插入学生的成绩\n");
printf("2、搜索学生成绩\n");
printf("3、打印所有学生的成绩\n");
printf("4、删除学生的成绩\n");
printf("5、退出学生成绩管理系统\n");
printf("*****************************************************\n");
scanf("%d",&choose);
switch(choose)
{
case 1:
printf("请您输入学生的编号:\n");
scanf("%d",&input_student_data.number);
printf("请您输入学生的姓名:\n");
scanf("%s",input_student_data.stu_name);
printf("请您输入学生的成绩:\n");
scanf("%d",&input_student_data.grade);
new_node = request_student_node(&input_student_data);
root = insert_node_to_tree(root,new_node);
break;
case 2:
printf("请输入学生的编号来查询学生成绩信息\n");
scanf("%d",&input_value);
find_node = find_tree_node(root,input_value);
if (find_node == NULL)
{
printf("找不到该学生的信息\n");
break;
}
printf("编号:%d,学生姓名:%s,学生成绩:%d\n",find_node->perfor_info.number,find_node->perfor_info.stu_name,find_node->perfor_info.grade);
break;
case 3:
printf("所有的学生的成绩信息为\n");
tree_for_each(root);
break;
case 4:
printf("请输入学生的编号来删除学生成绩信息\n");
scanf("%d",&input_value);
root = remove_tree_node(root,input_value);
break;
case 5:
goto log_out;
}
}
return 0;
log_out:
return 0;
}
实现功能如下
所有代码也给大家吧:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//定义一个记录学生成绩的结构体
struct stu_grade
{
char stu_name[30];//姓名
int grade;//成绩
int number;//编号(学号)
};
//定义一个二叉树的结构体
typedef struct student_list
{
struct student_list *lchild;//左孩子
struct student_list *rchild;//右孩子
int height;
struct stu_grade perfor_info;//学生结构体类型的数据
}student_node;
//记录节点的高度
#define MAX(A, B) ((A)>(B)?(A):(B))
int get_tree_height(student_node *root)
{
if(root == NULL)
return 0;
return MAX(get_tree_height(root->lchild), get_tree_height(root->rchild))+1;
}
//初始化二叉树
student_node *request_student_node(const struct stu_grade *value)
{
student_node *new_node;
new_node = malloc(sizeof(student_node));
if (new_node == NULL)
{
perror("没有申请到二叉树节点\n");
return NULL;
}
if (value != NULL)
{
new_node->perfor_info = *value;
new_node->lchild = NULL;
new_node->rchild = NULL;
}
return new_node;
}
//解决左左不平衡
student_node *tree_node_rotate_right(student_node *root)
{
student_node *tmp;
tmp = root->lchild;
root->lchild = tmp->rchild;
tmp->rchild = root;
tmp->height = get_tree_height(tmp);
root->height = get_tree_height(root);
return tmp;//返回新的root的地址给调用这个函数的人,用于更新新的root地址
}
//解决右右不平衡
student_node *tree_node_rotate_left(student_node *root)
{
student_node *tmp;
tmp = root->rchild;
root->rchild = tmp->lchild;
tmp->lchild = root;
tmp->height = get_tree_height(tmp);
root->height = get_tree_height(root);
return tmp;
}
//解决左右不平衡
student_node *tree_node_rotate_left_right(student_node *root)
{
root->lchild = tree_node_rotate_left(root->lchild);
root = tree_node_rotate_right(root);
return root;
}
//解决右左不平衡
student_node *tree_node_rotate_right_left(student_node *root)
{
root->rchild = tree_node_rotate_right(root->rchild);
root = tree_node_rotate_left(root);
return root;
}
//增加插入学生成绩数据
student_node *insert_node_to_tree(student_node *root,student_node *new_node)
{
if (root == NULL)
return new_node;
if(root ->perfor_info.number > new_node->perfor_info.number)
{
root->lchild = insert_node_to_tree(root->lchild,new_node);
}
else
{
root->rchild = insert_node_to_tree(root->rchild,new_node);
}
if(get_tree_height(root->lchild)-get_tree_height(root->rchild) == 2)//左不平衡
{
//如果插入的数据比跟的左树节点的数据要小,那他肯定是插入到root->lchild的左边去,出现了左左不平衡
if(new_node->perfor_info.number < root->lchild->perfor_info.number)//左左不平衡
{
root = tree_node_rotate_right(root);
}
else//否则则是插入到root->lchild的右边去,出现了左右不平衡
{
root = tree_node_rotate_left_right(root);
}
}
else if(get_tree_height(root->rchild)-get_tree_height(root->lchild) == 2)//右不平衡
{
if( new_node->perfor_info.number >= root->rchild->perfor_info.number)//右右不平衡
{
printf("出现右不平衡\n");
root = tree_node_rotate_left(root);
}
else//右左不平衡
{
root = tree_node_rotate_right_left(root);
}
}
root->height = get_tree_height(root);
return root;
}
//搜索查询学生信息
student_node *find_tree_node(student_node *root,int input_value)
{
if (root == NULL)
return NULL;
if (root->perfor_info.number > input_value)
{
return find_tree_node(root ->lchild,input_value);
}
else if (root->perfor_info.number < input_value)
{
return find_tree_node(root ->rchild,input_value);
}
return root;
}
//打印所有学生的信息(中序遍历打印)
void tree_for_each(student_node *root)
{
if (root == NULL)
{
return;
}
tree_for_each(root->lchild);
printf("编号:%d,学生姓名:%s,学生成绩:%d\n",root->perfor_info.number,root->perfor_info.stu_name,root->perfor_info.grade);
tree_for_each(root->rchild);
}
//删除学生成绩信息
student_node *remove_tree_node(student_node *root, int rm_value)
{
student_node *tmp;
if(root == NULL)//如果树为NULL则直接返回
return NULL;
if(root->perfor_info.number == rm_value)
{
if(root->lchild==NULL && root->rchild == NULL)
{
free(root);
return NULL;
}
else if(root->lchild != NULL)//如果有左子树
{
for(tmp=root->lchild; tmp->rchild != NULL; tmp=tmp->rchild);//用tmp来记录root的左子树当中的最右边的节点(也就是左树当中的最大值)
root->perfor_info.number = tmp->perfor_info.number;//将左子树中的最大值赋值到我们要删除的节点上(等同于覆盖了这个节点)
root->lchild = remove_tree_node(root->lchild, tmp->perfor_info.number);//递归的删除掉重复出来的这个节点,将左子树的数据更新进来
}
else//如果只有右子树
{
for(tmp=root->rchild; tmp->lchild != NULL; tmp=tmp->lchild);//用tcmp来记录root的右子树中的最左边的节点(也就是有树当中的最小值)
root->perfor_info.number = tmp->perfor_info.number;//将右子树中的最小值赋值到我们要删除的节点上(等同于覆盖了这个节点)
root->rchild = remove_tree_node(root->rchild, tmp->perfor_info.number);//递归的删除掉重复出来的这个节点,将右子树的数据更新进来
}
}
else if(rm_value < root->perfor_info.number)//如果删除的数据比这个节点要小,则继续往左边去删除节点
{
root->lchild = remove_tree_node(root->lchild, rm_value);
}
else//如果删除的数据比这个节点要大,则继续往右边去删除
{
root->rchild = remove_tree_node(root->rchild, rm_value);
}
//插入新节点结束后再判断是否出现不平衡
if(get_tree_height(root->lchild)-get_tree_height(root->rchild) == 2)//左不平衡
{
//如果插入的数据比跟的左树节点的数据要小,那他肯定是插入到root->lchild的左边去,出现了左左不平衡
if( get_tree_height(root->lchild->lchild)-get_tree_height(root->lchild->rchild) == 1)//左左不平衡
{
root = tree_node_rotate_right(root);
}
else//否则则是插入到root->lchild的右边去,出现了左右不平衡
{
root = tree_node_rotate_left_right(root);
}
}
else if(get_tree_height(root->rchild)-get_tree_height(root->lchild) == 2)//右不平衡
{
if( get_tree_height(root->rchild->rchild)-get_tree_height(root->rchild->lchild) == 1)//右右不平衡
{
root = tree_node_rotate_left(root);
}
else//右左不平衡
{
root = tree_node_rotate_right_left(root);
}
}
root->height = get_tree_height(root);
return root;//如果当前root这个节点不是我们删除的节点,我们便原封不动的返回出去
}
int main(void)
{
int choose,input_value;
struct stu_grade input_student_data;//定义一个学生结构体类型的数据用来缓存学生数据
student_node *root = NULL,*new_node,*find_node;
//初始化一个节点root为空
while(1)
{
printf("****************欢迎来到学生成绩管理系统************\n");
printf("请输入数字选择相应的指令\n");
printf("1、增加插入学生的成绩\n");
printf("2、搜索学生成绩\n");
printf("3、打印所有学生的成绩\n");
printf("4、删除学生的成绩\n");
printf("5、退出学生成绩管理系统\n");
printf("*****************************************************\n");
scanf("%d",&choose);
switch(choose)
{
case 1:
printf("请您输入学生的编号:\n");
scanf("%d",&input_student_data.number);
printf("请您输入学生的姓名:\n");
scanf("%s",input_student_data.stu_name);
printf("请您输入学生的成绩:\n");
scanf("%d",&input_student_data.grade);
new_node = request_student_node(&input_student_data);
root = insert_node_to_tree(root,new_node);
break;
case 2:
printf("请输入学生的编号来查询学生成绩信息\n");
scanf("%d",&input_value);
find_node = find_tree_node(root,input_value);
if (find_node == NULL)
{
printf("找不到该学生的信息\n");
break;
}
printf("编号:%d,学生姓名:%s,学生成绩:%d\n",find_node->perfor_info.number,find_node->perfor_info.stu_name,find_node->perfor_info.grade);
break;
case 3:
printf("所有的学生的成绩信息为\n");
tree_for_each(root);
break;
case 4:
printf("请输入学生的编号来删除学生成绩信息\n");
scanf("%d",&input_value);
root = remove_tree_node(root,input_value);
break;
case 5:
goto log_out;
}
}
return 0;
log_out:
return 0;
}