基于二叉树实现一个学生成绩信息管理系统

众所周知,二叉树在数据结构领域属于一个较难的课题,本文针对二叉树的基本操作逻辑,实现了一个基于二叉树的学生成绩管理系统,包含初始化增加删除打印等各大基本功能,和大家一起分享,小编也是个初学者,有什么不正确的地方望指正。

本代码用了大量的递归函数,小白慎进,毕竟这是个很掉头发的东西,可真让人头秃!!!

本代码实现五大功能,分别是:

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;
}

 

 

 

 

 

 

 

 

 

 

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值