学生成绩管理
以单链表作为存储结构,设计和实现某班某门课程成绩管理的完整程序。程序要求完成如下功能:
(1)创建成绩链表,学生数据包含学生的学号、姓名和成绩。
(2)可以在指定学号学生前插入学生成绩数据。 (3)可以删除指定学号的学生数据。 (4)可以计算学生的总数。
(5)可以按学号和姓名查找学生。 (6)可以显示所有学生的成绩。
(7)可以把学生成绩按从高到低的顺序排列。
此处的设计思想基本与顺序表相同,只是对保存学生成绩的线性表采用不同的存储结构实现。本例中用到的学生数据也是程序运行时由用户从键盘输入,保存到一个单链表中。学生结构体类型的定义与顺序表应用举例处的定义相同,用C语言描述如下:
typedef struct Student /*学生类型定义*/ { int score; /*成绩*/ char sno[5],sname[8]; /*学号,姓名*/ }Student;
当学生的学号为“#”时,也是表示数据输入的结束。单链表中保存的数据元素均为学生Student类型,则单链表定义如下:
typedef struct Node /*结点类型定义*/ { Student studentInfo; /*学生信息*/
struct Node *next; /*指向后继元素的指针域*/ }LinkList;
对学生的成绩按从高到低排序时,使用的也是直接插入排序思想。此外,为了排序后还能在原单链表上继续进行操作,这里是把单链表中的内容复制到一个新单链表中,对新单链表排序,原单链表不变。
下面是以单链表作为存储结构实现的学生某门课程成绩管理的完整C语言程序。 #include
typedef struct Student /*学生类型定义*/ { int score; /*成绩*/ char sno[5],sname[8]; /*学号,姓名*/ }Student;
typedef struct Node /*结点类型定义*/ { Student studentInfo; /*学生信息*/
struct Node *next; /*指向后继元素的指针域*/ }LinkList;
void display(LinkList *p) /*在屏幕上显示一个学生的成绩信息*/ { printf(\
printf(\ /*打印学号*/ printf(\
printf(\ /*打印姓名*/ printf(\
printf(\ /*打印成绩*/ }
void displayAll(LinkList *L) /*在屏幕上显示所有学生的成绩信息*/ { LinkList *p; p=L->next;
printf(\ while(p)
{ printf(\ /*打印学号*/ printf(\
printf(\ /*打印姓名*/ printf(\
printf(\ /*打印成绩*/ p=p->next; } }
LinkList *inputdata( ) /*输入学生信息*/ { LinkList *s=NULL ; /*s是指向新建结点的指针*/ char sno[5]; /*存储学号的数组*/ printf(\
printf(\ no: \ scanf(\ /*输入学号*/ if(sno[0]=='#') /*#结束输入*/ return s;
s=( LinkList *)malloc(sizeof(LinkList)); strcpy(s->studentInfo.sno,sno);
if(strlen(sno)>4) /*如果sno字符个数大于等于5,因为字符串没有'\\0'结束标志, 在读数据时将把姓名字符一起读到sno数组,因此做了如下处理*/
s->studentInfo.sno[4]='\\0';
printf(\ scanf(\ /*输入姓名*/ printf(\ scanf(\ /*输入成绩*/ return s; }
LinkList *createTailList( ) /*以尾插法建立带头结点的学生信息单链表*/ { LinkList *L,*s, *r; /*L头指针,r尾指针,s是指向新建结点的指针*/ L=( LinkList *)malloc(sizeof (LinkList)); /*建立头结点,申请结点存储空间*/ r=L; /*尾指针指向头结点*/
printf(\请输入学生成绩,当学号no为\\\时结束:\\n\\n \
while (1) /*逐个输入学生的成绩*/ { s=inputdata( ); if(!s) break; /*s为空时结束输入*/ r->next=s; /*把新结点插入到尾指针后*/ r=s; /*r 指向新的尾结点*/ }
r->next=NULL; /*尾指针的指针域为空*/ displayAll(L); /*显示所有学生信息*/ return L; }
Void locateElemByno(LinkList *L, char ch[5]) /*按学号查找学生的算法*/ { LinkList *p=L->next; /*从第一个结点开始查找*/
while ( p && (strcmp(p->studentInfo.sno,ch)!=0))/*p不空且输入学号与链表中学号不等*/ p = p ->next; if (!p) { printf(\ } else { display(p); /*显示查找到的学生信息*/ } }
void locateElemByname(LinkList *L, char sname[8])/*按姓名查找学生的算法*/ { LinkList *p=L->next; /*从第一个结点开始查找*/
while ( p&& (strcmp(p->studentInfo.sname,sname)!=0)) /*p不空且输入姓名与
链表中姓名不等*/
p = p ->next; if (!p)
{ printf(\ } else
{display(p); /*显示查找到的学生信息*/ } }
int lengthList (LinkList *L) /*求学生总人数的算法*/ { LinkList * p=L->next; /* p指向第一个结点*/ int j=0; while (p)
{ p=p->next; j++ ;} /* p所指的是第 j 个结点*/ return j; }
void insertElem ( LinkList *L, char ch[5]) /*在带头结点的单链表L中指定学号前插入学生*/ { LinkList *p,*s;
p=L; /*从头结点开始查找学号为ch的结点的前趋结点p */ while ((p->next) && (strcmp(p->next->studentInfo.sno,ch)!=0)) p = p ->next; s=inputdata(); /*输入欲插入学生信息*/ s->next=p->next; p->next=s; }
void deleteElem (LinkList *L, char ch[5]) /*删除给定学号的学生信息的算法*/ { LinkList *p,*q; p=L;
while ( (p->next)&&(strcmp(p->next->studentInfo.sno,ch)!=0 ))
{ p=p->next; /*从头结点开始查找学号为ch的结点的前趋结点p*/
}
if (!p->next) /* 已经扫描到表尾也没找到*/ { printf(\
}
else
{ q=p->next; /*q指向学号为ch的结点*/ printf(\ display(q);
p->next=q->next; /*改变指针*/
free(q); /*释放q占用空间 */ printf(\ displayAll(L); } }
void insertSort(LinkList *L) /*用直接插入排序思想把学生的成绩按从高到低排序,
结果保存在新有序链表中,原链表不变*/ { LinkList *L1,*p; /*L1有序链表的表头,p插入位置前结点*/ LinkList *q,*s; /*q欲插入L1中的结点*/ int len; len=lengthList (L) ; L1=( LinkList *)malloc(sizeof (LinkList)); /*建立头结点,申请结点存储空间*/ if (L->next) /*链表L非空*/ { /*生成有序链表的第一个结点*/ s=( LinkList *)malloc(sizeof (LinkList)); /*建立结点,申请结点存储空间*/ strcpy(s->studentInfo .sno ,L->next->studentInfo.sno);
strcpy(s->studentInfo .sname,L->next->studentInfo.sname); s->studentInfo .score =L->next->studentInfo.score; s->next =NULL;

