Skip to content

第六周作业

  1. (学生信息处理问题)有这样一种学生结构体类型,其数据成员有包括学号,姓名和3门课程的成绩。实现下列要求:

    • (a). 从键盘输入5个学生的信息,将这些同学的信息采用结构体数组的方式存储起来。

    • (b). 将学生信息按照学号重新排序,并且输出到控制台上。

    • (c). 输出每门课程最高分的学生信息。

    • (d). 输出每门课程的平均分。

    • (e). 按照总分输出学生排名。

c
#include<string.h> 
#include<stdio.h>
#include<stdlib.h>
typedef struct student_s {
    int id;
    char name[25];
    float score1;
    float score2;
    float score3;
} student_t;
void info_input(student_t * stu_arr,int len); //输入学生信息
void sort_by_id(student_t *stu_arr,int len); //按照学号排序
void print_arr(student_t *stu_arr,int len); // 打印数组
void find_max_score1(student_t *stu_arr, int len); //找score1最高分
void find_max_score2(student_t *stu_arr, int len); //找score2最高分
void find_max_score3(student_t *stu_arr, int len); //找score3最高分
void print_average_score(student_t *stu_arr, int len); //打印平均分
void sort_by_score(student_t *stu_arr, int len); //按照总分排序
int main(){
    student_t stu_arr[5];
    info_input(stu_arr,5);
    printf("-----------------------\n");
    sort_by_id(stu_arr,5);
    printf("-----------------------\n");
    find_max_score1(stu_arr,5);
    find_max_score2(stu_arr,5);
    find_max_score3(stu_arr,5);
    printf("-----------------------\n");
    print_average_score(stu_arr,5);
    printf("-----------------------\n");
    sort_by_score(stu_arr,5);
    return 0;
}
void info_input(student_t * stu_arr,int len){
    for(int i = 0; i < len; ++i){
        scanf("%d%s%f%f%f",
              &stu_arr[i].id,stu_arr[i].name, //由于name字段是字符数组,所以可以不用加&符号
              &stu_arr[i].score1,&stu_arr[i].score2,&stu_arr[i].score3);
    }
}
void sort_by_id(student_t *stu_arr,int len){
    // 这里使用了冒泡排序
    for(int i = len; i >= 1; --i){ // 依次遍历前len、len-1、... 3、2个元素
        for(int j = 0; j < i-1; ++j){ // 下标从0遍历到i-1,试图找到前i个数的最大值
            if(stu_arr[j].id > stu_arr[j+1].id){ //如果左边的元素比右边的大,则发生交换
                student_t temp = stu_arr[j];
                stu_arr[j] = stu_arr[j+1];
                stu_arr[j+1] = temp;
            }
        }
    }
    print_arr(stu_arr,5);
}
void print_arr(student_t *stu_arr,int len){
    for(int i = 0; i < len; ++i){
        printf("%d %s %g %g %g\n",
               stu_arr[i].id, stu_arr[i].name,
               stu_arr[i].score1, stu_arr[i].score2, stu_arr[i].score3);
    }
}
void find_max_score1(student_t *stu_arr, int len){
    int max_i = 0;
    int max_score1 = stu_arr[0].score1;
    for(int i = 1; i < len; ++i){
        if(stu_arr[i].score1 > max_score1){
            max_i = i;
            max_score1 = stu_arr[i].score1;
        }
    }
    printf("max score1: %d %s %g %g %g\n",
           stu_arr[max_i].id, stu_arr[max_i].name,
           stu_arr[max_i].score1, stu_arr[max_i].score2, stu_arr[max_i].score3);
}
void find_max_score2(student_t *stu_arr, int len){
    int max_i = 0;
    int max_score2 = stu_arr[0].score2;
    for(int i = 1; i < len; ++i){
        if(stu_arr[i].score2 > max_score2){
            max_i = i;
            max_score2 = stu_arr[i].score2;
        }
    }
    printf("max score2: %d %s %g %g %g\n",
           stu_arr[max_i].id, stu_arr[max_i].name,
           stu_arr[max_i].score1, stu_arr[max_i].score2, stu_arr[max_i].score3);
}
void find_max_score3(student_t *stu_arr, int len){
    int max_i = 0;
    int max_score3 = stu_arr[0].score3;
    for(int i = 1; i < len; ++i){
        if(stu_arr[i].score3 > max_score3){
            max_i = i;
            max_score3 = stu_arr[i].score3;
        }
    }
    printf("max score2: %d %s %g %g %g\n",
           stu_arr[max_i].id, stu_arr[max_i].name,
           stu_arr[max_i].score1, stu_arr[max_i].score2, stu_arr[max_i].score3);
}
void print_average_score(student_t *stu_arr, int len){
    float sum1 = 0;
    float sum2 = 0;
    float sum3 = 0;
    for(int i = 0; i < len; ++i){
        sum1 += stu_arr[i].score1;
        sum2 += stu_arr[i].score2;
        sum3 += stu_arr[i].score3;
    }
    printf("avg score1 = %g, avg score2 = %g, avg score3 = %g\n", sum1/len, sum2/len, sum3/len);
}
void sort_by_score(student_t *stu_arr, int len){
    for(int i = len; i >= 1; --i){ 
        for(int j = 0; j < i-1; ++j){
            if(stu_arr[j].score1 + stu_arr[j].score2 + stu_arr[j].score3 > 
               stu_arr[j+1].score1 + stu_arr[j+1].score2 + stu_arr[j+1].score3){
                student_t temp = stu_arr[j];
                stu_arr[j] = stu_arr[j+1];
                stu_arr[j+1] = temp;
            }
        }
    }
    print_arr(stu_arr,5);
}

下面是链表结点类型的声明:

c
typedef struct node_s {
  int data;
  struct node_s* next;
} node_t;
typedef struct link_list_s {
  node_t* phead;
  node_t* ptail;
} link_list_t;
  1. 假设存在两个链表,链表的各个结点数据域都是有序的。要求合并这两个链表,并且合并之后也是有序的。本题中不能重新申请堆空间。
c
void merge_list(link_list_t *l1, link_list_t *l2, link_list_t * result){
    node_t *pcur1 = l1->phead;
    node_t *pcur2 = l2->phead;
    while(pcur1 != NULL && pcur2 != NULL){
        //分别遍历两个链表,将较小的结点以尾插法的方式插入结果当中
        if(pcur1->data < pcur2->data){ 
            if(result->phead == NULL){
                result->phead = pcur1;
                result->ptail = pcur1;
            }
            else{
                result->ptail->next = pcur1;
                result->ptail = pcur1;
            }
            pcur1 = pcur1->next;
        }
        else {
            if(result->phead == NULL){
                result->phead = pcur2;
                result->ptail = pcur2;
            }
            else{
                result->ptail->next = pcur2;
                result->ptail = pcur2;
            }
            pcur2 = pcur2->next;
        }
    }
    //如果是第一个链表有剩余结点
    if(pcur1 != NULL){
        result->ptail->next = pcur1;
        result->ptail = l1->ptail;
    }
    //如果是第二个链表有剩余结点
    if(pcur2 != NULL){
        result->ptail->next = pcur2;
        result->ptail = l2->ptail;
    }
}
  1. 假设链表的长度大于4,要求找到倒数第4个结点。
c
void find_last_4th(link_list_t *l){
    node_t * ppre = l->phead; //慢指针指向第一个结点
    node_t * pcur; //快指针
    if(ppre && ppre->next && ppre->next->next && ppre->next->next->next){
        pcur = ppre->next->next->next;
        //一开始快指针在第4个位置,慢指针在第一个位置
    }
    else{
        printf("error, length less than 4!\n");
        return;
    }

    while(pcur != l->ptail){//快慢指针同速度后移,直到快指针到达倒数第一个结点
        pcur = pcur->next;
        ppre = ppre->next;
    }

    printf("the 4th last = %d\n", ppre->data);
}
  1. C语言学习 | week06_线性链表建立及正序输出
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//先设计链表的某一个结点
typedef struct node_s {
  int data;
  struct node_s* next;
} node_t;
typedef struct link_list_s {
  node_t* phead;
  node_t* ptail;
} link_list_t;
void tail_insert(link_list_t* plist, int data) {
  node_t* pnew_node = (node_t*)malloc(sizeof(node_t));
  pnew_node->next = NULL; 
  pnew_node->data = data;
  if (plist->phead == NULL) {
    plist->phead = pnew_node;
    plist->ptail = pnew_node;
  }
  else {
    plist->ptail->next = pnew_node;
    plist->ptail = pnew_node;
  }
}
void print_list(link_list_t* plist) {
  node_t* pcur = plist->phead;
  while (pcur != NULL) {
    printf("%d", pcur->data);
    if (pcur->next != NULL) { // 不是最后一个结点
      printf(" ");
    }
    pcur = pcur->next; // 每次需要将游标后移
  }
  printf("\n");
}
int main(){
    int d;
    link_list_t  list = {NULL,NULL};
    while(scanf("%d", &d), d > 0){ //按顺序插入就是做尾插法
        tail_insert(&list,d);
    }
    print_list(&list);
    return 0;
}
  1. C语言学习 | week06_线性链表的建立及逆序输出
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//先设计链表的某一个结点
typedef struct node_s {
  int data;
  struct node_s* next;
} node_t;
typedef struct link_list_s {
  node_t* phead;
  node_t* ptail;
} link_list_t;
void head_insert(link_list_t* plist, int data) {
  node_t* pnew_node = (node_t *)malloc(sizeof(node_t));
  pnew_node->next = NULL; 
  pnew_node->data = data;
  if (plist->phead == NULL) {
    plist->phead = pnew_node;
    plist->ptail = pnew_node;
  }
  else {
    pnew_node->next = plist->phead;
    plist->phead = pnew_node;
  }
}
void print_list(link_list_t* plist) {
  node_t* pcur = plist->phead;
  while (pcur != NULL) {
    printf("%d", pcur->data);
    if (pcur->next != NULL) { // 不是最后一个结点
      printf(" ");
    }
    pcur = pcur->next; // 每次需要将游标后移
  }
  printf("\n");
}
int main(){
    int d;
    link_list_t  list = {NULL,NULL};
    while(scanf("%d", &d), d > 0){ //逆序输入就是做头插法
        head_insert(&list,d);
    }
    print_list(&list);
    return 0;
}
  1. C语言学习 | week06_线性链表的查找
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node_s {
  int data;
  struct node_s* next;
} node_t;
typedef struct link_list_s {
  node_t* phead;
  node_t* ptail;
} link_list_t;
void tail_insert(link_list_t* plist, int data) {
  node_t* pnew_node = (node_t*)malloc(sizeof(node_t));
  pnew_node->next = NULL; //新结点的指针域一开始总是NULL
  pnew_node->data = data;
  if (plist->phead == NULL) {
    plist->phead = pnew_node;
    plist->ptail = pnew_node;
  }
  else {
    plist->ptail->next = pnew_node;
    plist->ptail = pnew_node;
  }
}
void find_bigger_x(link_list_t* plist, int x) {
  node_t* pcur = plist->phead;
  int flag = 0; // flag用来记录是否有比x大的元素
  while (pcur != NULL) {
      if(pcur->data > x){
          flag = 1;
          printf("%d ", pcur->data);
      }
      pcur = pcur->next;
  }
  if(flag == 0){
      printf("no found");
  }
  printf("\n");
}
int main(){
    int d, x;
    link_list_t  list = {NULL,NULL};
    while(scanf("%d", &d), d > 0){
        tail_insert(&list,d);
    }
    scanf("%d", &x);
    find_bigger_x(&list,x);
    return 0;
}
  1. C语言学习 | week06_线性链表的删除
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node_s {
    int data;
    struct node_s* next;
} node_t;
typedef struct link_list_s {
    node_t* phead;
    node_t* ptail;
} link_list_t;
void print_list(link_list_t* plist) {
    node_t* pcur = plist->phead;
    while (pcur != NULL) {
        printf("%d", pcur->data);
        if (pcur->next != NULL) { // 不是最后一个结点
            printf(" ");
        }
        pcur = pcur->next; // 每次需要将游标后移
    }
    printf("\n");
}
void tail_insert(link_list_t* plist, int data) {
    node_t* pnew_node = (node_t*)malloc(sizeof(node_t));
    pnew_node->next = NULL; //新结点的指针域一开始总是NULL
    pnew_node->data = data;
    if (plist->phead == NULL) {
        plist->phead = pnew_node;
        plist->ptail = pnew_node;
    }
    else {
        plist->ptail->next = pnew_node;
        plist->ptail = pnew_node;
    }
}
void list_delete(link_list_t* plist, int x) {
    node_t *pcur = plist->phead; //用来遍历所有结点
    node_t *ppre = NULL; //用来记录pcur结点的前驱,如果NULL说明pcur为第一个结点
    while(pcur != NULL){
        if(pcur->data > x){ // 这个情况需要删除结点
            if(pcur == plist->phead){ // 根据是否需要修改phead和ptail来分类讨论
                // 如果删除的是第一个结点,只用改phead的指向
                node_t *old = pcur;
                plist->phead = pcur->next; //将phead后移
                pcur = pcur->next; //pcur也需要后移
                free(old);
            }
            else if(pcur != plist->phead){
                // 如果删除的不是第一个结点,则需要找到被删结点的前驱结点,修改其指针域
                node_t *old = pcur;
                ppre->next = pcur->next; //修改前驱结点的指针域,跳过pcur
                if(pcur == plist->ptail){ 
                    plist->ptail = ppre;
                }
                pcur = pcur->next; //pcur后移,ppre不变位置 
                free(old);
            }
        }
        else{
            //如果不需要删除结点,则pcur和ppre都需要后移
            ppre = pcur;
            pcur = pcur->next;
        }
    }
}
int main() {
    int d,x;
    link_list_t list = {NULL, NULL};
    while(scanf("%d", &d), d > 0){
        tail_insert(&list,d);
    }
    scanf("%d", &x);
    list_delete(&list,x);
    print_list(&list);
    return 0;
}
  1. C语言学习 | week06_链表插入和删除
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node_s {
    int data;
    struct node_s* next;
} node_t;
typedef struct link_list_s {
    node_t* phead;
    node_t* ptail;
} link_list_t;
void print_list(link_list_t* plist) {
    node_t* pcur = plist->phead;
    while (pcur != NULL) {
        printf("%d", pcur->data);
        if (pcur->next != NULL) { // 不是最后一个结点
            printf(" ");
        }
        pcur = pcur->next; // 每次需要将游标后移
    }
    printf("\n");
}
void tail_insert(link_list_t* plist, int data) {
    node_t* pnew_node = (node_t*)malloc(sizeof(node_t));
    pnew_node->next = NULL; //新结点的指针域一开始总是NULL
    pnew_node->data = data;
    if (plist->phead == NULL) {
        plist->phead = pnew_node;
        plist->ptail = pnew_node;
    }
    else {
        plist->ptail->next = pnew_node;
        plist->ptail = pnew_node;
    }
}
void insert_x(link_list_t *plist, int x, int k){
    node_t *pcur = plist->phead; 
    for(int i = 1; i < x; ++i){ 
        pcur = pcur->next;
    }//循环结束之后,pcur指向链表中第x个结点(当x大于等于1时,不用考虑头插的可能性)
    //准备好新结点
    node_t* pnew_node = (node_t*)malloc(sizeof(node_t));
    pnew_node->next = NULL; 
    pnew_node->data = k; 
    //将新结点插入pcur和pcur后继之间
    pnew_node->next = pcur->next;
    pcur->next = pnew_node;
    if(pnew_node->next == NULL){ //假如插入的是最后一个结点
        plist->ptail = pnew_node;
    }
}
void delete_y(link_list_t *plist, int y){
    node_t *pcur = plist->phead;
    if(y == 1){ //删除第一个结点需要做头部删除
        plist->phead = pcur->next;
        if(pcur->next == NULL){
            plist->ptail = NULL;
        }
        free(pcur);
    }
    else{
        for(int i = 1; i < y-1; ++i){ //找到第y-1个结点
            pcur = pcur->next;
        }
        node_t *old = pcur->next;
        pcur->next = old->next;
        if(pcur->next == NULL){
            plist->ptail = pcur;
        }
        free(old);
    }
}
int main() {
    int n,d,x,y,k;
    link_list_t list = {NULL,NULL};
    scanf("%d", &n);
    for(int i = 0; i < n; ++i){
        scanf("%d", &d);
        tail_insert(&list,d);
    }
    scanf("%d%d",&x,&y);
    scanf("%d",&k);
    insert_x(&list,x,k);
    delete_y(&list,y);
    print_list(&list);
    return 0;
}
  1. C语言学习 | week06_猴子选大王
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node_s {
    int data;
    struct node_s* next;
} node_t;
typedef struct link_list_s {
    node_t* phead;
    node_t* ptail;
} link_list_t;
void tail_insert(link_list_t* plist, int data) {
    node_t* pnew_node = (node_t*)malloc(sizeof(node_t));
    pnew_node->next = NULL;
    pnew_node->data = data;
    if (plist->phead == NULL) {
        plist->phead = pnew_node;
        plist->ptail = pnew_node;
    }
    else {
        plist->ptail->next = pnew_node;
        plist->ptail = pnew_node;
    }
}
void print_list(link_list_t* plist) {
  node_t* pcur = plist->phead;
  while (pcur != NULL) {
    printf("%3d", pcur->data);
    if (pcur->next != NULL) { // 不是最后一个结点
      printf("-> ");
    }
    pcur = pcur->next; // 每次需要将游标后移
  }
  printf("\n");
}
int circle(link_list_t *plist, int m){
    node_t *pcur = plist->phead;//pcur是当前位置 从头开始遍历,到ptail之后回到phead
    node_t *ppre = plist->ptail;//ppre是pcur的前一个位置
    int count = 1;
    while(plist->phead != plist->ptail){ //当链表中有不止一个结点的时候持续循环
        if(count != m){//pcur不用被删除
            ppre = pcur; 
            // pcur后移
            if(pcur == plist->ptail){ //如果当前是ptail,则下一个为phead
                pcur = plist->phead;
            }
            else{
                pcur = pcur->next;
            }
            ++count;
        }
        else { //要删除pcur结点
            if(pcur == plist->phead){ // 假如pcur为第一个结点 则ppre是最后一个结点
                node_t *old = plist->phead;
                pcur = pcur->next;
                plist->phead = pcur;
                free(old);
            }
            else{ //假如pcur不是第一个结点
                node_t *old = pcur;
                if(pcur == plist->ptail){
                    pcur = plist->phead; //下一个访问是phead
                    plist->ptail = ppre; //原来的ptail被删除
                    ppre->next = NULL;
                }
                else{
                    pcur = pcur->next;
                    ppre->next = pcur;
                }
                free(old);
            }
            count = 1; 
        }
    }
    return plist->phead->data;
}
int main(){
    link_list_t list = {NULL,NULL};
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; ++i){
        tail_insert(&list,i);
    }
    printf("%d",circle(&list,m));
}