数组与链表学生成绩管理系统

引言

因为学生管理系统类似数据库,需要实现增删改查,来管理其数据,所以该管理系统也应该实现这四个功能,这里使用数组实现,且具体实现如下。

源代码

具体源代码存放在gitee仓库地址如下

学生成绩管理系统之目录

1
2
3
4
5
6
7
8
9
10
11
12
13
//菜单
void menu()
{
printf("===============\n");
printf("1、学生成绩录入\n");
printf("2、学生成绩删除\n");
printf("3、学生成绩修改\n");
printf("4、学生成绩查询\n");
printf("5、学生成绩打印\n");
printf("6、排 序\n");
printf("0、退 出\n");
printf("===============\n");
}

这里使用printf()函数直接输出

学生成绩管理系统之录入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//录入成绩
void add()
{

for (int i = 0; i < max - actual;i++)
{
int temp,k=0;//temp用来存放学号
//当数组有成绩时
if (actual>0) {
printf("请输入第%d位学生的学号为:", actual+1);
scanf("%d", &temp);
//判断是否有重复学号
while (temp!=student[k][0]&&k<actual)
{
k++;
}
if(temp==student[k][0])
{
//如果在数组中找到相同学号,则跳出本次循环重新输入
printf("学号重复请重新输入!\n");
continue;
}
else
{
student[actual][0]=temp;
printf("请输学号为%d的同学成绩:", student[actual][0]);
scanf("%d", &student[actual][1]);
actual++;

}
//判断是否继续
getchar();
printf("还有继续么(y/n):");
char c = getchar();
if (c == 'y' || c == 'Y')
{
;
}
else if (c == 'n' || c == 'N')
{
break;
}
else
{
printf("输入错误,即将退出录入系统!\n");
break;
}
}
//当数组没有成绩时
else if (actual==0) {
printf("请输入第%d位学生的学号为:", i + 1);
scanf("%d", &temp);
//查找并判断是否有重复的学号
while (temp!=student[k][0]&&k<actual)
{
k++;
}
if(temp==student[k][0])
{
//如果在数组中找到相同学号,则跳出本次循环重新输入
printf("学号重复请重新输入!\n");
continue;
}
else
{
student[i][0]=temp;
printf("请输学号为%d的同学成绩:", student[i][0]);
scanf("%d", &student[i][1]);
actual++;

}
getchar();
printf("还有继续么(y/n):");
char c = getchar();
if (c == 'y' || c == 'Y') { ;
} else if (c == 'n' || c == 'N') {
break;
} else {
printf("输入错误,即将退出录入系统!\n");
break;
}
}


}
}

这里需要定义一个二维数组,将学号放第一列,成绩放低0列,还需用到循环与条件判断来判断是否还要继续输入,并且定义一个存放实际人数变量actual,每次录入加1人

学习管理系统之修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//修改成绩
void alter() {
while (1) {
int number, i = 0;
//输入要修改成绩的学号
printf("请输入要修改的学号:");
scanf("%d", &number);
//开始查找与学号配对的成绩位置
while (number != student[i][0] && i < actual)
{
i++;
}
//判断是否有该学号的成绩
if (number == student[i][0])
{
//有该学号则输入修改后的成绩
printf("请输入要修改的成绩:");
scanf("%d", &student[i][1]);
}
else
{
//没有则输出查无此人
printf("查无此人\n");
}
//判断是否继续修改
getchar();
printf("还有继续么(y/n):");
char c = getchar();
if (c == 'y' || c == 'Y')
{
;
}
else if (c == 'n' || c == 'N')
{
break;
}
else
{
printf("输入错误,即将退出修改系统!\n");
}

}
}

这里使用循环一个一个学号对比,找到后然后将修改成绩覆盖到要修改的成绩位置,没找到则输出查无此人

学生成绩管理系统之删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//删除成绩
void delete()
{
while (1) {
int number, i = 0;
//输入要删除成绩的学号
printf("请输入要删除成绩的学号:");
scanf("%d", &number);
//查找学号
while (number != student[i][0] && i < actual)
{
i++;
}
//判断是否有此学号
if (number == student[i][0])
{
//如果有,则后面的成绩覆盖要删除的成绩,后面依次往前挪
for(;i<actual;i++)
{
student[i][0]=student[i+1][0];
student[i][1]=student[i+1][1];

}
printf("删除成功!\n");
}
else
{
//如果没有,则输出查无此人
printf("查无此人!\n");
}
//删除一个成绩则实际人数减一
actual--;
//判断是否继续删除
getchar();
printf("还有继续么(y/n):");
char c = getchar();
if (c == 'y' || c == 'Y')
{
//如果输入为y则执行空语句
;
}
else if (c == 'n' || c == 'N')
{
break;
}
else
{
printf("输入错误,即将退出删除系统!\n");
break;

}

}
}

删除类似修改,只是将成绩覆盖改成,下面的成绩全部往上移1格,这里每删除一个人则实际人数actual减1人

学生成绩管理系统之查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void find()
{
while (1) {

int number, i = 0;
//输入要查找成绩的学号
printf("请输入要查找的学号:");
scanf("%d", &number);
//查找学号对应的成绩位置
while (number != student[i][0] && i < actual)
{
i++;
}
//判断是否有与之对应的学号
if (number == student[i][0])
{
//有则输出成绩
printf("学号为%d的成绩为:%d\n",number,student[i][1]);
}
else
{
//没有则输出查无此人
printf("查无此人\n");
}
//判断是否继续
getchar();
printf("还有继续么(y/n):");
char c = getchar();
if (c == 'y' || c == 'Y')
{
;
}
else if (c == 'n' || c == 'N')
{
break;
}
else
{
printf("输入错误,即将退出查找系统\n");

}

}

}

查找也是利用学号,一一对比找学号,然后打印该学号位置的成绩

学生成绩管理系统之打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void print()
{
//用for循环依次打印出实际人数的学号成绩对应表
int i;
printf("成绩表如下(学号-成绩):\n");
for(i=0;i<actual;i++)
{
printf("%4d%4d\n",student[i][0],student[i][1]);
}
float average=0.0;
float sum=0.0;
for(int j=0;j<actual;j++)
{
sum=sum+student[j][1];
}
average=sum/actual;
printf("全班的平均成绩为%2f\n",average);
}

这里使用for循环一一换行打印

学生成绩管理系统之排序

冒泡排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void maopao()
{
int temp=0,num=0; //初始化存放成绩和学号的临时变量
for(int i=0;i<actual-1;i++) //遍历实际人数-1次
{
for(int j=0;j<actual-i-1;j++) //遍历实际人数减-1-1次;2人一组对比所以比要再减1次
{
if(student[j][1]>student[j+1][1]) //判断前后两数的大小,如果前面的成绩比后面成绩大
{
//交换成绩
temp=student[j][1];
student[j][1]= student[j+1][1];
student[j+1][1]=temp;
//交换学号
num=student[j][0];
student[j][0]=student[j+1][0];
student[j+1][0]=num;
}
}
}
print(); //打印成绩
}

两两比对,交换位置,然后循环重新再比对,注意点是,外循环与内循环都比实际人数少1位

选择排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//选择排序
void choice()
{
int a=0,b=0,min;
for(int i=0;i<actual-1;i++)
{
min=i; //假设最小值位置
for(int j=i+1;j<actual;j++) //开始遍历找所有的值对比
{
if(student[j][1]<student[min][1]) //如果后面的数小于最小值,则记录最小值的位置
{
min=j;
}
}
if(min!=i) //如果最小值不等于最开始的位置,则
{
//交换学号
b=student[min][0];
student[min][0]=student[i][0];
student[i][0]=b;
//交换成绩
a=student[min][1];
student[min][1]=student[i][1];
student[i][1]=a;

}
}
print(); //打印成绩
}

选择排序是将最小的元素挑出来与没排序的第一位交换位置,它会不断的选择剩余元素中的最小者

插入排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//插入排序
void insert()
{

int i,j;
int temp,id;
for(i=1;i<actual;i++)
{
if(student[i][1]<student[i-1][1]) //如果后面的数小于前面的数
{
temp=student[i][1]; //保存后面的数到temp
id=student[i][0]; //对应的学号保存到ou
for(j=i-1;student[j][1]>temp;j--) //开始将前面到数移位,当前面的数大于temp就开始循环,直到有比temp大的数和最前面则跳出循环
{
student[j+1][1]=student[j][1]; //将成绩向后移
student[j+1][0]=student[j][0]; //学号向后移
if(j<0) //当最小到数移动到第一位后
{
break; //退出循环
}
}
student[j+1][1]=temp; //将temp的值插入到比temp大的数的前面
student[j+1][0]=id; //将对应的学号插入到对应的位置

}
}
print();
}

插入在比自己小的数的前面
首先将后面比前面小的数存放在另一个变量,然后前面比这个数大的数依次往后挪,直到比自己小的数,然后放入到其后面。

归并排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//归并排序
//分治 递归
void merge_split(){
split(student,1,actual);
print();
}
//将数组用递归拆成单个元素
void split(int arr[][2],int p,int q)
{
int mid;
//确保拆成单个元素
if(arr== NULL ||p>q||p==q)
{
return ;
}
mid=(p+q)/2;
split(arr,p,mid);
split(arr,mid+1,q);
merge(arr,p,mid,q);
}
//排序归并在一起
void merge(int arr[][2],int p,int mid,int q){
int i,j,k;
int L,R;
//定义临时存放左右数组的数组
int LL[max][2];
int RR[max][2];
//定义左右数组长度
L=mid-p+1;
R=q-mid;
//将左边数组存放到临时数组
for(i=0;i<L;i++)
{
LL[i][1]=arr[p-1+i][1];
LL[i][0]=arr[p-1+i][0];
}
//将右边数组存放到临时数组
for(i=0;i<R;i++)
{
RR[i][1]=arr[mid+i][1];
RR[i][0]=arr[mid+i][0];
}
i=0;
j=0;
for(k=p;k<=q;k++)
{
//当LL与RR没有元素时,放入原来数组
if(i==L)
{
arr[k-1][1]=RR[j][1];
arr[k-1][0]=RR[j][0];
j++;

}
else if(j==R)
{
arr[k-1][1]=LL[i][1];
arr[k-1][0]=LL[i][0];
i++;
}
else
{
//当LL与RR还有元素时,放入原来数组
if(LL[i][1]<RR[j][1])
{
arr[k-1][1]=LL[i][1];
arr[k-1][0]=LL[i][0];
i++;
}
else
{
arr[k-1][1]=RR[j][1];
arr[k-1][0]=RR[j][0];
j++;
}
}
}
}

先用递归拆分数组,然后用循环归并并排序数组
递归是不断把数组拆成左右两部分,其中写的if判断是用来限制,分成一个元素后不可再分。
归并是先记录左右素组的大小,然后分别放到另一个数组中,然后归并到原来的数组,分别对左右数组的第一个元素比较
当剩下元素没用完时会添加再数组后面

功能选择

功能选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int select()
{
while (1)
{
int i;
menu();
printf("请输入要选择的功能:");
scanf("%d",&i);
switch (i)
{
case 1: add();break;
case 2: delete();break;
case 3: alter();break;
case 4: find();break;
case 5: print();break;
case 6: short_1();break;
case 0: return 0;
default: printf("输入错误,请重新输入");break;
}
}
}

这里将多个函数封装到了功能选择函数中
用switch来实现多种功能的选择

排序选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//排序算法目录
int short_1()
{
int i;
printf("===============\n");
printf("1、冒泡排序\n");
printf("2、选择排序\n");
printf("3、插入排序\n");
printf("4、归并排序\n");
printf("===============\n");
printf("请输入要使用的排序方法:");
scanf("%d",&i);
switch (i) {
case 1: maopao();break;
case 2: choice();break;
case 3: insert();break;
case 4: merge_split();break;
default: printf("输入错误,请重新输入");break;

}

}

与功能选择类似

函数的入口main

1
2
3
int main() {
select();
}

所有内容都是在main函数中使用的,所以要在main中导入之前的函数

源代码

具体源代码存放在gitee仓库地址如下

目录

目录就不用多说,用以前的打印就好了

1
2
3
4
5
6
7
8
9
10
11
12
void menu()
{
printf("===============\n");
printf("1、学生成绩录入\n");
printf("2、学生成绩删除\n");
printf("3、学生成绩修改\n");
printf("4、学生成绩查询\n");
printf("5、学生成绩打印\n");
printf("6、释 放 空 间\n");
printf("0、退 出\n");
printf("===============\n");
}

链表录入

先要定义结构体

1
2
3
4
5
6
7
8
9
10
typedef struct student
{
//信息域
int num;
char name[10];
char sex;
float score;
//指针域
struct student *next;
}stu;

然后需要定义头指针

1
stu *head=NULL;

然后开始判断链表是否为空

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
void add()
{
//定义选择变量
int choose;
//定义尾指针
stu *last=NULL;
while (1)
{
//当链表为空时,head当next成员指向last,last为新节点,用来存放数据,last当next成员指向空
if(head==NULL)
{
//给第一个节点分配空间,当链表只有一个节点时,这个节点就是这个链表当last
last=(stu *)malloc(sizeof (stu));
last->next=NULL;
head=(stu *)malloc(sizeof (stu));
head->next=last;
//录入信息到信息域
printf("请输入学号:");
scanf("%d",&last->num);
printf("请输入姓名:");
scanf("%s",last->name);
getchar();
printf("请输入性别(男:M,女:F):");
scanf("%c",&last->sex);
printf("请输入成绩:");
scanf("%f",&last->score);
}
//当链表不为空时,找到最后一个节点,last的next成员分配空间,然后最新的将last这个指针指向刚刚建立的空间为最新的last,然后最新的last的next成员指向null
else if(head!=NULL)
{
//查找链表的最后一个节点
last=head->next;
while(last->next!=NULL)
{
last=last->next;
}
//分配新节点空间
last->next=(stu *)malloc(sizeof (stu));
//标注新的last
last=last->next;
last->next=NULL;
//录入信息到信息域
printf("请输入学号:");
scanf("%d",&last->num);
printf("请输入姓名:");
scanf("%s",last->name);
getchar();
printf("请输入性别(男:M,女:F):");
scanf("%c",&last->sex);
printf("请输入成绩:");
scanf("%f",&last->score);
}
getchar();
printf("还有继续么(y/n):");
char c = getchar();
if (c == 'y' || c == 'Y')
{
//如果输入为y则执行空语句
;
}
else if (c == 'n' || c == 'N')
{
break;
}
else
{
printf("输入错误,即将退出删除系统!\n");
break;

}
}
}

其中也需要定义last尾指针,这个指针在录入时代表的意思是存放最后一个节点的地址
其中malloc()内存分配函数需要强行改变类型切需要引用头文件

1
#include <stdlib.h>

删除成绩

删除后面的都依照数组实现的学生管理系统逻辑推理写出,就不过多解释,有不懂的可以在联系我

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
void delete()
{
while (1)
{
int num;
if(head==NULL)
{
printf("学生成绩表无信息\n");
break;
}
printf("请输入要删除成绩的学号:");
scanf("%d",&num);
stu *temp;
temp=head;
while(temp->next!=NULL)
{
if(num==temp->next->num)
{
stu *del=temp->next;
temp->next=temp->next->next;
free(del);
break;
}
temp=temp->next;
}
if(temp==NULL)
{
printf("查无此人");
}

getchar();
printf("还有继续么(y/n):");
char c = getchar();
if (c == 'y' || c == 'Y')
{
//如果输入为y则执行空语句
;
}
else if (c == 'n' || c == 'N')
{
break;
}
else
{
printf("输入错误,即将退出删除系统!\n");
break;

}
}
}

修改成绩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//修改成绩
void alter()
{
while (1)
{
int num;
if(head==NULL)
{
printf("学生成绩表无信息\n");
break;
}
printf("请输入要修改成绩的学号:");
scanf("%d",&num);
stu *temp;
temp=head->next;
while(temp!=NULL)
{
if(num==temp->num)
{
printf("请输入要修改的成绩:");
scanf("%f",&temp->score);
break;
}
temp=temp->next;
}
if(temp==NULL)
{
printf("查无此人");
}

getchar();
printf("还有继续么(y/n):");
char c = getchar();
if (c == 'y' || c == 'Y')
{
//如果输入为y则执行空语句
;
}
else if (c == 'n' || c == 'N')
{
break;
}
else
{
printf("输入错误,即将退出删除系统!\n");
break;

}
}
}

打印链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//链表当输出
void print()
{
stu *temp;
temp=head->next;
printf("学号\t\t\t\t姓名\t\t性别\t\t成绩\n");
while(temp!=NULL)
{
printf("%-16d%-8s%-8c%-8.2f\n",temp->num,temp->name,temp->sex,temp->score);
temp=temp->next;
}
return;

}

释放内存空间

1
2
3
4
5
6
7
8
9
10
11
12
//释放空间
void release()
{
stu *temp_2;
while(head!=NULL)
{
temp_2=head;
head=head->next;
free(temp_2);
}

}

成绩查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//查找成绩
void find()
{
while (1)
{
int num;
if(head==NULL)
{
printf("学生成绩表无信息\n");
break;
}
printf("请输入要查找的学号:");
scanf("%d",&num);
stu *temp;
temp=head->next;
while(temp!=NULL)
{
if(num==temp->num)
{
printf("你要查找的学生信息如下:\n");
printf("学号\t\t\t\t姓名\t\t性别\t\t成绩\n");
printf("%-16d%-8s%-8c%-8.2f\n",temp->num,temp->name,temp->sex,temp->score);
break;
}
temp=temp->next;
}
if(temp==NULL)
{
printf("查无此人");
}

getchar();
printf("还有继续么(y/n):");
char c = getchar();
if (c == 'y' || c == 'Y')
{
//如果输入为y则执行空语句
;
}
else if (c == 'n' || c == 'N')
{
break;
}
else
{
printf("输入错误,即将退出删除系统!\n");
break;

}
}
}

功能选择与程序入口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//选择功能
int select()
{
while (1)
{
int i;
menu();
printf("请输入要选择的功能:");
scanf("%d",&i);
switch (i)
{
case 1: add();break;
case 2: delete();break;
case 3: alter();break;
case 4: find();break;
case 5: print();break;
case 6: release();break;
case 0: return 0;
default: printf("输入错误,请重新输入");break;
}
}
}
int main()
{
select();
}