一、有10个学生,每个学生的数据包括学号、姓名、3门课的成绩,从键盘输入10个学生数据,要求输出3门课程总平均成绩,以及最高分的学生的数据(包括学号,姓名,3门课成绩,平均分数)
分析:定义学生结构体,含有3个属性,需要完成输入输出,以及平均成绩、最高分的计算
#include<stdio.h>
#include<stdlib.h>
#define N 10
struct student{
char number[6];
char name[8];
float score[3];
float avr;
}stu[N];
int main(void){
int i,j,maxi;
float sum,max,average;
//input data
for(i=0;i<N;i++){
printf("input scores of student %d:\n",i+1);
printf("NO.:");
scanf("%s",stu[i].number);
printf("name:");
scanf("%s",stu[i].name);
for(j=0;j<3;j++){
printf("score %d:",j+1);
scanf("%f",&stu[i].score[j]);
}
}
//计算
average =0;
max =0;
maxi=0;
for(i=0;i<N;i++){
sum=0;
for(j=0;j<3;j++)
sum+=stu[i].score[j]; //计算第i个学生总分
stu[i].avr=sum/3.0;
average+=stu[i].avr;
if(sum>max){ //找分数最高者
max=sum;
maxi=i; //将此学生的下标保存在maxi
}
}
average/=N;
//output
printf("NO.name score1 score2 score3 average\n");
for(i=0;i<N;i++){
printf("%5s%10s",stu[i].number,stu[i].name);
for(j=0;j<3;j++)
printf("%9.2f",stu[i].score[j]);
printf("%8.2f\n",stu[i].avr);
}
printf("average =%5.2f\n",average);
printf("the highest score is:student %s,%s\n",stu[maxi].number,stu[maxi].name);
printf("his score are:%6.2f,%6.2f,%6.2f,average:%5.2f.\n",stu[maxi].score[0],stu[maxi].score[1],stu[maxi].score[2],stu[maxi].avr);
return 0;
}
二、13个人围城一圈,从第1个人开始顺序报号1,2,3。凡报到3者退出圈子。找出后留在圈子中的人原来的序号。要求用链表处理。
#include<stdio.h>
#define N 13
struct person{
int number;
int nextp;
}link[N+1];
int main(){
int i,count,h;
for(i=1;i<=N;i++){
if(i==N)
link[i].nextp=1;
else
link[i].nextp=i+1;
link[i].number=i;
}
printf("\n");
count=0;
h=N;
printf("sequence that persons leave the circle:\n");
while(count<N-1){
i=0;
while(i!=3){
h=link[h].nextp;
if(link[h].number);
i++;
}
printf("%4d",link[h].number);
link[h].number=0;
count++;
}
printf("\n the last one is ");
for(i=1;i<=N;i++)
if(link[i].number)
printf("%3d",link[i].number);
printf("\n");
return 0;
}
3.编写函数del删除动态链表中指定结点
解:比如一队伍小孩(a,b,c,d,e)手拉手,如果某一个小孩(比如C)想离队,二队形保持不变。只要将C 的手从两边脱开,B改为与D 拉手即可
与此相仿,从一个动态链表中删去一个结点,并不是真正从内存抹去,而实把它从链表分离开来,只要撤销原来的链接关系即可
若想从已建立的动态链表删除指定的结点,可指定学号作为删除结点的标志。
例如,输入20表示删除编号为20的结点。
从p指向的第一个结点开始,检查该结点中的num的值是否等于输入的要求删除的那个学号。如果相等就将该结点删除,
若不等,就将指针后移一个结点,如此重复直到遇到表尾为止。
可设立两个指针遍历p1和p2,先使p1指向第一个结点。如果要删除的不是第一个结点,则使p1后指向下一个结点(将p1->next赋值给p1),再此之前应将p1的值赋给p2,使p2指向刚才检查簂的结点。如此依次后移p,直到找到所要删除的结点或检查完全部链表都找不到要删除的结点为止。
如果找到某一结点是要删除的结点,还分两种情况:
①要删的是第一个结点(p1的值=head的值),则应将p1->next赋给head。这时head指向原来的第2个结点。第1个结点虽然仍存在,但它已与链表脱离。因为链表中没有一个结点或头指针指向它。虽然p1还指向它,它也指向第2个结点,但不具有意义。
现在链表的一个结点原来是的第二个结点,原来第一个结点已“丢失”,
②如果删除的不是第1个结点,则将p1->next给p2->next, p2->next改为指向p1->next所指向结点。p1所指向的结点不再是链表的一部分。
#include<stdio.h>
#define N 13
struct student{
long num;
float score;
struct student * next;
};
int n;
struct student *del(struct student *head,long num)
{
struct student * p1,*p2;
if(head==NULL){ //是空表
printf("\n list null \n");
return (head);
}
p1=head; //使p1指向第1个结点
while(num!=p1->num&&p1->next!=NULL){//p1指向的不是索要找的结点且后面还有结点
//p1后移一个结点
p2=p1;
p1=p1->next;
}
if(num==p1->num){ //找到对应结点
if(p1==head) head=p1->next; //若p1指向的是首结点,把第2个结点地址赋予head
else //否则将下一个结点地址赋给前一结点地址
p2->next=p1->next;
printf("delete:%ld\n",num);
n=n-1;
}
else printf("%ld not been found!\n",num); //找不到该结点
return (head);
}
/*函数的类型是指向student类型数据的指针,它的值是链表的头指针.
函数参数为head和要删除的学号num
head的值可能在函数执行过程中被该边(当删除第1个结点时)*/
4.实现链表的建立、输出、删除和插入
#include<stdio.h>
#include<malloc.h>
#define LEN sizeof(struct student)
struct student *del(struct student *head,long num);
struct student *creat();
void print(struct student *head);
struct student *insert(struct student *head,struct student *stud);
struct student{
long num;
float score;
struct student *next;
};
int n;
int main(){
struct student *creat();
struct student *del(struct student*,long);
struct student *insert(struct student*,struct student*);
void print(struct student*);
struct student *head,*stu;
long del_num;
printf("printf records:\n");
head=creat();
print(head);
printf("\n input the deleted number:");
scanf("%ld",&del_num);
while(del_num!=0){
head=del(head,del_num);
print(head);
printf("input the deleted number:");
scanf("%ld",&del_num);
}
printf("\n input the inserted record:");
stu=(struct student*)malloc(LEN);
scanf("%ld,%lf",&stu->num,&stu->score);
while(stu->num!=0){
head=insert(head,stu);
print(head);
printf("input the inserted record:");
stu=(struct student*)malloc(LEN);
scanf("%ld,%f",&stu->num,&stu->score);
}
return 0;
}
//建立链表的函数
struct student *creat(){
struct student *head;
struct student *p1,*p2;
n=0;
p1=p2=(struct student*)malloc(LEN); //开辟一个新单元,并使p1,p2指向它
scanf("%ld,%f",&p1->num,&p1->score);
head=NULL;
while(p1->num!=0){
n=n+1;
if(n==1) head=p1;
else p2->next=p1;
p2=p1;
p1=(struct student*)malloc(LEN);
scanf("%ld,%lf",&p1->score);
}
p2->next=NULL;
return(head);
}
//定义删除结点的del函数
struct student *del(struct student *head,long num)
{
struct student * p1,*p2;
if(head==NULL){ //是空表
printf("\n list null ! \n");
return (head);
}
p1=head; //使p1指向第1个结点
while(num!=p1->num&&p1->next!=NULL){//p1指向的不是索要找的结点且后面还有结点
//p1后移一个结点
p2=p1;
p1=p1->next;
}
if(num==p1->num){ //找到对应结点
if(p1==head) head=p1->next; //若p1指向的是首结点,把第2个结点地址赋予head
else //否则将下一个结点地址赋给前一结点地址
p2->next=p1->next;
printf("delete:%ld\n",num);
n=n-1;
}
else printf("%ld not been found!\n",num); //找不到该结点
return(head);
}
//插入结点函数
struct student *insert(struct student *head,struct student *stud){
struct student *p0,*p1,*p2;
p1=head; //p1指向第1个结点
p0=stud; //指向要插入的结点
if(head=NULL){ //原来的链表是空表
head=p0;p0->next=NULL; //使p0指向的结点作为头结点
}
else{
while((p0->num)&&(p1->next!=NULL))
{ p2=p1; //使p2指向刚才p1指向的结点
p1=p1->next; //p1后移一个结点
}
if(p0->num<=p1->num){
if(head==p1) head=p0; //插入到原来第1个结点之前
else p2->next=p0; //插到p2指向的结点之后
p0->next=p1;
}
else{
p1->next=p0;
p0->next=NULL; //插到最后的结点之后
}
}
n=n+1; //结点数加1
return (head);
}
//打印
void print(struct student *head){ //输出链表的函数
struct student *p;
printf("\n now,these %d records are :\n",n);
p=head;
if(head!=NULL)
do{
printf("%ld %5.1f",p->num,p->score);
p=p->next;
}while(p!=NULL);
}