学生成绩档案管理系统 实验准备

实验内容

建立一个学生成绩档案管理系统,系统满足以下要求:

  1. 学生信息录入,信息包括学号、姓名、专业、四门课成绩、总分、名次
  2. 系统可对学生信息浏览、增加、删除和修改
  3. 按学生成绩确定名次及信息输出,双向冒泡排序、希尔排序、快速排序、堆排序
  4. 要求可对学生信息查询,根据学号或姓名进行查找
  5. 信息修改仅可修改四门课成绩
  6. 文件存取学生信息

项目分析

  • 读取学生信息(系统将磁盘文件中保存的学生成绩信息读取到内存中)
  • 新增学生信息(学号、姓名、专业、四门课成绩)并保存
  • 对学生总成绩进行排名(根据四门课成绩计算总分,通过四种方式:双向冒泡排序、希尔排序、快速排序、堆排序进行排序)
  • 浏览学生信息(按排名输出信息:学号、姓名、专业、四门课成绩、总分、名次)
  • 删除学生信息(删除学生)
  • 修改学生信息(修改时只能修改四门课的成绩)
  • 查找学生信息(根据学号或姓名进行查找)

编程语言的选择

  • 编程语言:C++
  • 开发工具:Visual Studio

项目思路

1.确定数据结构

(1)学生信息的结构体

属性名称数据类型
学号numberchar
姓名namechar
专业majorchar
大学英语成绩mark1int
高数成绩mark2int
数据结构成绩mark3int
C++成绩mark4int
总成绩sumMarkint
排名rankint

代码如下:

struct student
{
	char number[20];       //学号
	char name[20];         //姓名
	char major[20];        //专业
	double mark1;          //英语成绩
	double mark2;          //高数成绩
	double mark3;          //数据结构成绩
	double mark4;          //C++成绩
	double sumMark;        //总分
	int rank;              //排名
};

(2)链式存储结构的定义

struct Node
{
	student data;         //节点的数据域
	Node* next;           //节点的指针域
};

最初数据结构选择使用链表,但在程序的编写过程中,发现希尔排序和堆排序不太适合用于链表的排序,因此改为使用数组作为数据结构。

2.基本功能的实现

学生成绩档案管理系统的基本功能即为对学生信息的增删改查。
代码如下:

void insertNodeByHead(Node* listHeadNode, student data)
{
    Node *newNode= createNode(data);
	//连接
	newNode->next = listHeadNode->next;
	listHeadNode->next = newNode;
}
/*通过姓名查找并删除*/
void deleteNodeByAppoinName(Node* listHeadNode, char*name)
{
	Node* posFrontNode = listHeadNode;
	Node* posNode = listHeadNode->next;
	if (posNode == nullptr)
	{
		cout << "无相关内容,无法删除!\n";
		return;
	}
	else
	{
		while (strcmp(posNode->data.name,name))
		{
			posFrontNode = posNode;
			posNode = posFrontNode->next;
			if (posNode == nullptr)
			{
				cout<< "无相关内容,无法删除!\n";
				return;
			}
		}
		posFrontNode->next = posNode->next;
		delete posNode;

	}
}
/*通过学号查找*/
Node* searchNodeByAppoinNum(Node* listHeadNode, char* num)
{
	Node* pMove = listHeadNode->next;
	if (pMove == nullptr)
		return pMove;
	else
	{
		while (strcmp(pMove->data.number, num))
		{
			pMove = pMove->next;
			if (pMove == nullptr)
				break;
		}
		return pMove;
	}
}
/*通过姓名查找*/
Node* searchNodeByAppoinName(Node* listHeadNode, char* name)
{
	Node* pMove = listHeadNode->next;
	if (pMove == nullptr)
		return pMove;
	else
	{
		while (strcmp(pMove->data.name, name))
		{
			pMove = pMove->next;
			if (pMove == nullptr)
				break;
		}
		return pMove;
	}
}

3.排序的实现

(1)双向冒泡排序

算法原理

  1. 是传统冒泡气泡排序的双向进行,先让气泡排序由左向右进行,再来让气泡排序由右往左进行,如此完成一次排序的动作。
  2. 使用left与right两个旗标来记录左右两端已排序的元素位置。

算法步骤

  1. 比较相邻两个元素的大小。如果前一个元素比后一个元素大,则两元素位置交换
  2. 对数组中所有元素的组合进行第1步的比较
  3. 奇数趟时从左向右进行比较和交换
  4. 偶数趟时从右向左进行比较和交换
  5. 当从左端开始遍历的指针与从右端开始遍历的指针相遇时,排序结束

代码实现

(2)希尔排序

算法原理
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

算法步骤

  1. 根据初始序列的长度,选定一个递减增量序列t1,t2,t3…tk,其中ti>tj,tk = 1。
  2. 根据选定的增量序列元素个数k,对初始序列进行k趟排序。
  3. 根据增量序列的值ti,每趟排序将初始序列划分成若干个元素的子序列,对这些子序列使用插入排序。

(3) 快速排序

算法原理
快速排序是一种分治的排序算法。它将一个数组分成两个子数组,将两部分独立的排序,两个子数组都有序时,整个数组也就自然有序了。

算法步骤

  1. 从数组中选取一个主元
  2. 根据主元将数组切分成两部分,大于或等于主元的数组元素集中到数组右边,小于主元的数组元素集中到数组的左边
  3. 对左右两边的元素进行递归排序

(4)堆排序

算法原理
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

算法步骤

  1. 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。
  2. 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。

4.文件读写的实现

  • 构造用于文件读、写的两个函数
  • 通过调用链插入函数,将文件内容添加到链表中
  • 通过将链表内容打印到文件内的方式,达到存放学生信息的目的

代码如下:

void readInformFile(const char* fileName, Node* listHeadNode)
{
	FILE* fp = fopen(fileName, "r");
	if (fp == nullptr)
	{
		fp = fopen(fileName, "w");
	}
	
	student tempData;
	while (fscanf(fp,"%s\t%s\t%s\t%d\t%d\t%d\t%d\t%d\t%d\n", tempData.number , tempData.name ,tempData.major , &tempData.mark1 , &tempData.mark2 ,&tempData.mark3 , &tempData.mark4 , &tempData.sumMark , &tempData.rank)!=EOF)
	{
		insertNodeByHead(listHeadNode, tempData);
		memset(&tempData, 0, sizeof(tempData));
	}
	fclose(fp);
}

void saveInfoToFile(const char* fileName, Node* listHeadNode)
{
	FILE* fp = fopen(fileName, "w");
	Node* pMove = listHeadNode->next;
	
	while (pMove)
	{
		fprintf(fp, "%s\t%s\t%s\t%d\t%d\t%d\t%d\t%d\t%d\n", pMove->data.number, pMove->data.name, pMove->data.major, pMove->data.mark1, pMove->data.mark2, pMove->data.mark3, pMove->data.mark4, pMove->data.sumMark, pMove->data.rank);
		pMove = pMove->next;
	}
	fclose(fp);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值