一、什么是数组、顺序表与链表
首先一定要分清楚什么是数组、顺序表与链表,学习C语言的小伙伴一般都是先进入数组的学习再进行结构体,C语言大作业多采用了结构体数组来构建学生信息数据库,在数据结构中则采用了顺序表或链表的形式,对于很多学习过数据结构的同学仍然无法分清楚这三者的关系,今天我们以三段代码来讲解。
1、数组
如下图所示代码,构建了一个学生结构体,包含学号、姓名、数学、语文、英语,定义出三个学生结构体,后续只要对三个数组进行调用修改即可,使用较为简便,缺点:因为不知道实际的学生数量,如果多定义则占用内存空间,少定义则很难再去添加。
typedef struct student
{
char num[10];
char name[10];
int math;
int chinese;
int english;
}STU;
STU a[3];
2、顺序表
先来看一个普通的顺序表,如下图,可以发现如果不对datatype予以结构体定义,其可存储的数据类型非常有限,因此加上单个学生的结构体定义后,可使用的灵活性增加,但是本人以为顺序表和结构体数组似乎并无很大的区别,不过是对学生的数量及所有个体进行封装在一个结构体内,其大小也无法改变,虽然书中有对顺序表的插入与删除,可深追后发现,其实并没有增加或删除内存而仅仅进行赋值与删值,因此如果你追求数据结构有个更好的成绩,我推荐你使用链表。
#define max 100
typedef struct
{
char name[10];
char num[10];
int english;
int math;
}datatype;
typedef struct
{
datatype a[max];
int size;
}STU;
3. 链表
直接看代码,构建一个学生结构体,不同于之前,里面多了一个next指针,通过尾插、头插法可以构建一个链表,优点:可以动态增加或减少学生数量,占用内存为合理化,缺点:构建较为麻烦。
typedef struct student
{
char name[10];
char num[10];
int english;
int math;
struct student* next;
}STU;
二、使用链表的大作业分析
1.下文所讲解的代码问题
对一个学生成绩表实现添加、修改、删除和排序和查找的功能
要求:
(1)分析需求,写出用到的数据结构;
(2)对排序(如冒泡法,其他快速算法)和查找(如顺序查找,二分查找)写出算法描述;
(3)排序按分数由高到低,查找按姓名;
2.需求分析与方法介绍及实现的代码
- 构建单链表存储学生各项信息:
我采用的方法是带头结点的链表,初始化采用尾插法进行构建
首先构建学生结构体与指向下一个学生的指针
typedef struct student
{
char stuid[16];//学号
char name[16];//学生姓名
int score;//学生成绩
struct student* next;//指向下一个学生的指针
}Stu;
接下来尾插法构建带头结点的学生链表
/*通过尾插法,建立一个带头结点的学生链表*/
Stu* init()
{
Stu* head; //构建头结点
head = (Stu*)malloc(sizeof(Stu));
head->next = NULL;
Stu* p;
p = head;
Stu* q;
printf("请输入学生个数:");
int i;
scanf("%d", &i);
printf("学号 姓名 成绩\n");
while (i--)
{
q = (Stu*)malloc(sizeof(Stu));
scanf("%s", &q->stuid);
scanf("%s", &q->name); //扫描很多的学生信息
scanf("%d", &q->score);
p->next = q;
p = q;
}
p->next = NULL;
return head;
}
运行所需的键盘输入如图所示
- 对学生成绩查找,从而添加删除与修改:
添加采用:通过顺序查找查找要添加到位置,注:对头结点插入与其他结点不太相同;删除采用:free结点,构建链表使用动态内存分配,只需要链接新的结点后再删除原结点即可;修改时采用:顺序查找,先找到该结点,再进行修改学生信息。
/*对学生信息查找*/
Stu* find(Stu* head, char a[])
{
Stu* p = head->next;
while (p && (strcmp(p->name, a) != 0))
p = p->next;
if (p)
return p;
return NULL;
}
/*对学生信息进行插入操作*/
void* insert(Stu* head, char a[])
{
Stu* q, * p;
q = find(head, a);
if (!q)
{
printf("未查找到该学生,无法进行插入操作\n");
}
else
{
p = (Stu*)malloc(sizeof(Stu));
printf("请依次输入要插入的学生的学号、姓名、成绩:");
scanf("%s %s %d", p->stuid, p->name, &(p->score));
p->next = q->next;
q->next = p;
printf("插入成功,进行更新后,学生信息如下:\n");
display(head);
}
}//此函数只能实行对非头位置的插入操作
/*对学生信息进行插入操作*/
void* inser(Stu* head)
{
Stu* p;
p = (Stu*)malloc(sizeof(Stu));
printf("请依次输入要插入的学生的学号、姓名、成绩:");
scanf("%s %s %d", p->stuid, p->name, &(p->score));
p->next = head->next;
head->next = p;
}//此函数只能实行对头位置的插入操作
/*对学生信息进行修改操作*/
void* alter(Stu* head, char a[])
{
Stu* q;
q = find(head, a);
if (q)
{
printf("请输入要修改的学生的新的信息,即顺序输入学号、姓名、成绩:");
scanf("%s %s %d", q->stuid, q->name, &(q->score));
printf("修改成功,进行更新后,学生信息如下:\n");
display(head);
}
else
printf("未查找到该学生,修改失败,");
}
/*对学生信息进行删除操作*/
Stu* delet(Stu* head, char a[])
{
Stu* q;
Stu* pre = head;
q = head->next;
while (q && (strcmp(q->name, a) != 0))
{
pre = q;
q = q->next;
}
if (q)
{
pre->next = q->next;
free(q);
printf("删除成功,进行更新后,学生信息如下:\n");
display(head);
}
else
printf("未查找到该学生,删除失败,");
}
当然由于比较菜,我对插入学生的部分写了两个函数,分别为插入头结点与其他节点的,其实可以放一起的整合在一个函数,就教给大家拓展啦。
- 排序
采用冒泡排序法,通过不断更新尾结点位置(每次最小值排到最后,即尾结点向前移动一位),每次从头位置(非头结点)进行排序到新的尾结点,即可完成排序。
/*对学生进行成绩排序*/
void C_sort(Stu* p)
{
Stu* begin = p->next;
Stu* end = NULL;
char a[16];//中间变量用于交换
int b;//中间变量用于交换
while (p->next->next != end)
{
while (begin->next != end) //冒泡排序法
{
if (begin->score < begin->next->score)
{
strcpy(a, begin->name);
strcpy(begin->name, begin->next->name);
strcpy(begin->next->name, a);/* 以上为对名字交换*/
strcpy(a, begin->stuid);
strcpy(begin->stuid, begin->next->stuid);
strcpy(begin->next->stuid, a);/* 以上为对学号交换*/
b = begin->score;
begin->score = begin->next->score;
begin->next->score = b;
}
begin = begin->next;
}
end = begin;
begin = p->next;
}
}
4.特殊说明:本程序含报错功能,即如果所输入的学生姓名不在学生系统存储,程序会进行报错,告诉“使用者”,未查找到该学生。在运行结果处,进行了测试。
三、总结
程序的主函数没有开放给大家,其实函数块都写好后,主函数不过是进行多级调用与循环,如果想显得逼格高一点,可以适当加一些配字与程序报错功能,例如下图。
如果想获取整个程序及使用方法的可以点击下方链接,我把报告进行了打包,含有代码与使用说明