【项目任务】
编写一个函数sort(),功能是按分数的高低排列学生的记录,低分在前。学生的记录由学号和成绩组成。
【设计思路】
学生的记录由学号和成绩组成,N名学生的数据已在主函数中放入结构体数组x中。编写一个函数sort( ),用来对结构体数组x进行排序,采取的排序算法为选择排序法。
【程序代码】
#include <stdio.h>
#define N 16 /*定义一个符号常量,表示学生的总人数*/
struct student /*定义一个结构体类型,用来表示学生信息*/
{
char num[10]; /*结构体的成员,用来表示学生的学号*/
int s ; /*结构体的成员,用来表示学生的成绩*/
};
typedef struct student STU;/*typedef 声明新的类型名STU*/
void sort(STU *a) /*a为一个结构体指针,STU 等价于struct student*/
{
int i,j;
STU temp;
for(i=0;i<N;i++)
for(j=i+1;j<N-1;j++)
if(a[i].s>a[j].s) /*比较两个学生的成绩,确保低分在前*/
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
main()
{
/* 定义一个结构体数组,它的初始化与二维数组有点类似*/
STU x[N]={{"GA005",88},{"GA003",64},{"GA002",77},{"GA004",89},
{"GA001",54},{"GA007",72},{"GA008",72},{"GA006",65},
{"GA015",83},{"GA013",95},{"GA012",55},{"GA014",68},
{"GA011",78},{"GA017",53},{"GA018",92},{"GA016",82}};
int i;
sort(x); /*对数组x进行排序*/
/* 输出结构体数组x中的数据*/
for(i=0;i<N;i++)
{
printf("%s:%2d ",x[i].num,x[i].s); /*引用结构体成员*/
if((i+1)%4==0) printf("\n");
}
printf("\n");
}
【运行结果】
GA017:53 GA001:54 GA012:55 GA003:64
GA006:65 GA014:68 GA007:72 GA008:72
GA002:77 GA011:78 GA015:83 GA005:88
GA004:89 GA018:92 GA013:95 GA016:82
【知识拓展】
1.结构体是一种构造数据类型,也是用户自定义的数据类型。一个结构体类型其实是由若干个成员组成的。从本案例中,要学会如何定义结构体类型,如何定义结构体变量、结构体数组、结构体的指针。对于结构体变量、数组、指针的用法与前面讲过的普通变量、数组、指针完全相同,只不过换了一种构造数据类型。
2.本案例中的结构体类型的标识符为struct student或STU,两者是等价的。
3.引用结构体成员有两种方式:一种是通过结构体变量名,如x.s;另一种是通过指向结构体变量的指针,如p->s或(*p).s。本案例中,在输出结构体数组x中的数据的for循环中,输出语句可以改写为printf("%s:%2d",(x+i)->num,(x+i)->.s);,其中x+i为指向数组x中第i个元素的指针。
【项目任务】
N名学生的成绩已在主函数中放入一个带头节点的链表结构中,h指向链表的头节点。编写函数fun( ),功能是求出平均分,由函数值返回。例如,若学生的成绩是85、76、69、91、72、64、87,则平均分应该是78.625。
【设计思路】
程序分为三个部分:创建链表,输出链表,遍历链表求平均值。
【程序代码】
#include <stdlib.h>
#include <stdio.h>
#define N 8
struct slist /*定义一个结构体,该数据类型用来描述链表中的节点信息*/
{
double s; /*数据域*/
struct slist *next; /*指针域,用来存放下一个节点的地址*/
};
typedef struct slist STREC;/*typedef 声明新的类型名STREC*/
double fun(STREC *h) /*指针h指向链表头*/
{
double sum=0.0;
int count=0;
STREC *p;
p=h->next; /*指针p指向链表的第一个节点*/
/*遍历链表*/
while(p!=NULL) /*最后一个节点的指针域的值为NULL*/
{
sum+=p->s; /*累加学生成绩*/
p=p->next; /*指针p移向下一个节点*/
count++; /*计数器加1*/
}
return sum/count; /*返回平均分*/
}
STREC *creat(double *s) /*创建链表*/
{
STREC *h,*p,*q;
int i;
/*创建链表头,注意:链表头节点数据域一般不存放数据*/
h=p=(STREC*)malloc(sizeof(STREC));
/*在for循环中,共创建了N个节点,并将这些节点连接成一个链表*/
for(i=0;i<N;i++)
{
q=(STREC*)malloc(sizeof(STREC));/*申请堆空间*/
q->s=s[i]; /*数据域存放学生成绩*/
p->next=q; /*最后一个节点的指针域指向新节点*/
p=q; /*更新p的值,让p指向新链表的最后一个节点*/
}
p->next=NULL; /*链表最后一个节点的指针域的值为NULL*/
return h; /*返回链表头指针*/
}
void outlist(STREC *h) /*输出链表中的数据*/
{
STREC *p;
p=h->next; /*跳过链表的头节点,因为头节点不存放数据*/
printf("head");
/*遍历链表*/
do
{
printf("->%g",p->s);
p=p->next; /*输出各成绩*/
} while(p!=NULL);
printf("\n");
}
main()
{
double s[N]={85,76,69,85,91,72,64,87},ave;
STREC *h;
h=creat(s); /*创建链表*/
outlist(h); /*输出链表中的学生成绩*/
ave=fun(h); /*求链表中所有学生的平均分*/
printf("ave=%6.3f\n",ave);
}
【运行结果】
head->85->76->69->85->91->72->64->87
ave=78.625
【知识拓展】
链表是一种常用且非常重要的数据结构,它能够根据实际需要进行动态的存储分配,因而较静态的存储分配的数组具有更好的可适应性和更高的存储利用率。链表中的各元素在内存中可以不连续存放。通过链表头节点,就可以找到链表中任意一个节点。
链表中的每个元素称为节点,每个节点由数据域和指针域构成,数据域存放节点自身的信息,即用户的实际数据;指针域则指向其后继节点的地址,如图9-1所示。
图9-1 节点构成图
指针head指向链表的头节点,将最后一个节点的指针域置为NULL,作为链表结束的标志,如图9-2所示。
图9-2 指针指向图
链表结构动态地分配存储空间,即在用户需要时才申请一个节点的存储空间。动态申请和释放存储空间时需要使用malloc( )函数、calloc( )函数和free( )函数等C语言库函数。