解决要求苛刻的结构任务

Solving demanding structure task

给出结构:

struct Date {
  int day, month, year;
};
struct Subject {
  int id;
  char name_of_subject[100];
  double ects;
};
struct Grade {
  char namesurname[100];
  int grade_value;
  struct Subject subject;
  struct Date date;
};

有必要编写一个函数 digits_in_date 来接收成绩结构数组。对于所有通过的科目总计 30 个或更多 ECTS 学分的学生(他们的成绩为 6 或更高),有必要从数组中排除(不改变顺序!)那些日期包含不同数字的最小数目。例如,日期 2020 年 2 月 20 日仅包含两个不同的数字(2 和 0)。如果他们有多个成绩的日期具有相同(最小)位数,则应从数组中删除所有此类成绩。可以根据名字和姓氏查出成绩属于同一个学生(假设两个学生的名字和姓氏相同,那么就是同一个学生)。假设数据是有效的(有效日期、有效成绩、ects学分不为负等)不允许辅助数组。做直方图时只允许辅助数组。

示例:

struct Grade arr[3] = {
      {"Luc Manning", 10, {1, "Physics", 25}, {19, 1, 2020}},
      {"Kaia Feeney", 8, {1, "Math", 25}, {19, 1, 2020}},
      {"Luc Manning", 7, {2, "Linear Algebra", 10}, {11, 1, 2020}}};

解释:

Luc Manning 的 ECTS 总分是 35,所以我们检查他的科目日期中有多少个不同的数字。 Physics 有 4 个,Linear Algebra 有 3 个不同的日期数字,所以 Linear Algebra 应该去掉。 Kaia Feeney ECTS 总分是 25,所以我们什么都不检查。

输出将是:

Luc Manning - Physics
Kaia Feeney - Math

说明: 创建一个辅助函数,使用直方图确定日期中不同数字的数量。然后是计算 ECTS 学分数量的辅助函数,最后是弹出函数。这将使您的任务变得更加容易。

我在代码中遇到的唯一问题是我的程序删除了错误的主题,而其余任务的算法是正确的。 一半的代码只是自动测试:)代码不是那么长。

编辑: @pm100做了一个可以省400行代码的函数,加上我对原代码的修改,现在的代码是:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>

struct Date {
  int day, month, year;
};
struct Subject {
  int id;
  char name_of_subject[100];
  double ects;
};
struct Grade {
  char namesurname[100];
  int grade_value;
  struct Subject subject;
  struct Date date;
};

int num_digit(int n) {
  int num = 0;
  while (n != 0) {
    num++;
    n /= 10;
  }
  return num;
}

int check_digits(int d, int m, int y) {
  char dateStr[10];
  sprintf(dateStr, "%02d%02d%04d", d, m, y);
  int count[10] = {0};
  for (int i = 0; i < strlen(dateStr); i++) {
    char ch = dateStr[i];
    count[ch - '0']++;
  }
  int num = 0;
  for (int i = 0; i < 10; i++) {
    if (count[i] > 0)
      num++;
  }
  return num;
}

double credits(struct Grade arr[], int n, int i) {
  int j;
  double sum = arr[i].subject.ects;
  for (j = i + 1; j < n; j++)
    if (strcmp(arr[j].namesurname, arr[i].namesurname) == 0)
      sum += arr[j].subject.ects;
  return sum;
}

int find_min(struct Grade arr[], int n, int i) {
  int j,
      min = check_digits(arr[i].date.day, arr[i].date.month, arr[i].date.year);
  for (j = i + 1; j < n; j++)
    if (strcmp(arr[j].namesurname, arr[i].namesurname) == 0)
      if (check_digits(arr[j].date.day, arr[j].date.month, arr[j].date.year) <
          min)
        min = j;
  return min;
}

int digits_in_date(struct Grade arr[], int n) {
  int i, j, k, min;
  double sum_ects;
  for (i = 0; i < n; i++) {
    sum_ects = credits(arr, n, i);
    if (sum_ects >= 30) {
      min = find_min(arr, n, i);
      for (j = 0; j < n; j++)
        if (strcmp(arr[j].subject.name_of_subject,
                   arr[min].subject.name_of_subject) == 0) {
          for (k = j + 1; k < n; k++)
            arr[k - 1] = arr[k];
          j--;
          n--;
        }
    }
  }
  return n;
}

int main() {
  int i, s;
  printf("\nAT1: Trivial case\n");
  struct Grade arr1[3] = {
          {"Luc Manning", 10, {1, "Physics", 25}, {19, 1, 2020}},
          {"Kaia Feeney", 8, {1, "Math", 25}, {19, 1, 2020}},
          {"Luc Manning", 7, {2, "Linear Algebra", 10}, {11, 1, 2020}}};
  s = digits_in_date(arr1, 3);
  for (i = 0; i < s; i++)
    printf("%s - %s\n", arr1[i].namesurname, arr1[i].subject.name_of_subject);

  printf("\nAT2: We must not observe the same student more than once\n");
  struct Grade arr2[4] = {
      {"Mujo Suljic", 10, {1, "Uvod u programiranje", 25}, {19, 1, 2020}},
      {"Fata Fatic", 8, {1, "Uvod u programiranje", 25}, {19, 1, 2020}},
      {"Mujo Suljic", 7, {2, "Inzenjerska fizika", 10}, {11, 1, 2020}},
      {"Mujo Suljic", 10, {3, "Inzenjerska matematika", 6}, {1, 9, 2020}}};
  s = digits_in_date(arr2, 4);
  for (i = 0; i < s; i++)
    printf("%s - %s\n", arr2[i].namesurname, arr2[i].subject.name_of_subject);
    printf("CORRECT:\nMujo Suljic - Uvod u programiranje\nFata Fatic - Uvod u programiranje\nMujo Suljic - Inzenjerska matematika\n");

  printf("\nAT3: Multiple successive ejections\n");
  struct Grade arr3[6] = {
      {"Mujo Suljic", 10, {1, "Uvod u programiranje", 25}, {2, 2, 2020}},
      {"Mujo Suljic", 6, {5, "Osnove elektrotehnike", 25}, {20, 2, 2022}},
      {"Fata Fatic", 8, {1, "Uvod u programiranje", 25}, {19, 1, 2020}},
      {"Mujo Suljic", 7, {2, "Inzenjerska fizika", 10}, {11, 1, 2020}},
      {"Mujo Suljic", 10, {3, "Inzenjerska matematika", 6}, {20, 1, 2020}},
      {"Fata Fatic", 8, {4, "Inzenjerska matematika", 25}, {9, 9, 2021}}};
  s = digits_in_date(arr3, 6);
  for (i = 0; i < s; i++)
    printf("%s - %s %g\n", arr3[i].namesurname, arr3[i].subject.name_of_subject,
           arr3[i].subject.ects);
    printf("CORRECT:\nMujo Suljic - Inzenjerska fizika 10\nMujo Suljic - Inzenjerska matematika 6\n");

  printf("\nAT4: Array with one element\n");
  struct Grade arr4[1] = {
      {"John Smith", 10, {1, "Subject 1", 29}, {19, 11, 1991}}};
  s = digits_in_date(arr4, 1);
  printf("%d ", s);
  arr4[0].subject.ects = 31;
  s = digits_in_date(arr4, 1);
  printf("%d\n", s);
 printf("CORRECT:\n1 0\n");

  printf(
      "\nAT5: We don't eject anything out, no one has 30 credits in total\n");
  struct Grade arr5[6] = {
      {"Mujo Suljic", 10, {1, "Uvod u programiranje", 25}, {20, 2, 2020}},
      {"Pero Peric", 6, {5, "Osnove elektrotehnike", 25}, {20, 2, 2020}},
      {"Fata Fatic", 8, {1, "Uvod u programiranje", 25}, {19, 1, 2020}},
      {"Mujo Suljic", 7, {2, "Inzenjerska fizika", 1}, {11, 1, 2020}},
      {"Mujo Suljic", 10, {3, "Inzenjerska matematika", 2}, {20, 1, 2020}},
      {"Fata Fatic", 8, {4, "Inzenjerska matematika", 2}, {19, 1, 2020}}};
  s = digits_in_date(arr5, 6);
  printf("s: %d\n", s);
  printf("AT5 again: Inzenjerska fizika now carries 4 ECTS credits so Mujo has "
         "the required number of credits\n");
  arr5[3].subject.ects = 4;
  s = digits_in_date(arr5, 6);
  for (i = 0; i < s; i++)
    printf("%s - %s %g\n", arr5[i].namesurname, arr5[i].subject.name_of_subject,
           arr5[i].subject.ects);
           printf("CORRECT:\ns: 6\nAT5 again: Inzenjerska fizika now carries 4 ECTS credits so Mujo has "
         "the required number of credits\nPero Peric - Osnove elektrotehnike 25\nFata Fatic - Uvod u programiranje 25\nMujo Suljic - Inzenjerska fizika 4\n"
"Mujo Suljic - Inzenjerska matematika 2\nFata Fatic - Inzenjerska matematika 2\n");

  //
  printf("\nAT6: Mujo Suljic did not pass Injzenjerska fizika, he does not "
         "have 30 ECTS credits\n");
  struct Grade arr6[6] = {
      {"Mujo Suljic", 10, {1, "Uvod u programiranje", 25}, {20, 2, 2020}},
      {"Pero Peric", 6, {5, "Osnove elektrotehnike", 25}, {20, 2, 2020}},
      {"Fata Fatic", 8, {1, "Uvod u programiranje", 25}, {19, 1, 2020}},
      {"Mujo Suljic", 5, {2, "Inzenjerska fizika", 10}, {11, 1, 2020}},
      {"Mujo Suljic", 10, {3, "Inzenjerska matematika", 4}, {20, 1, 2020}},
      {"Fata Fatic", 8, {4, "Inzenjerska matematika", 25}, {19, 1, 2020}}};
  s = digits_in_date(arr6, 6);
  for (i = 0; i < s; i++)
    printf("%s - %s %g\n", arr6[i].namesurname, arr6[i].subject.name_of_subject,
           arr6[i].subject.ects);
            printf("CORRECT:\nMujo Suljic - Uvod u programiranje 25\nPero Peric - Osnove elektrotehnike 25\n"
"Mujo Suljic - Inzenjerska fizika 10\nMujo Suljic - Inzenjerska matematika 4\n");
  return 0;
}

我只得到 AutoTest1 - AT1 的正确输出(与示例相同),其余的 AT 都是错误的。 你能帮我修改一下使其正常工作吗?

这是我的计数函数

转换为字符串,然后在 count[]

中创建分布 'histogram'

然后统计非0的个数

int count_digits(int d, int m, int y)
{
    char dateStr[10];
    sprintf(dateStr,"%02d%02d%04d", d, m, y);
    int count[10] = { 0 };
    for (int i = 0; i < strlen(dateStr); i++) {
        char ch = dateStr[i];
        count[ch - '0']++;
    }
    int tally = 0;
    for (int i = 0; i < 10; i++)
    {
        if (count[i] > 0)
            tally++;
    }
    return tally;
}

节省大约 380 行

我认为您误解了说明。你认为你必须拒绝一个学生除了最大的一切,不,你必须拒绝最小的。

对于 at2

    {"Mujo Suljic", 10, {1, "Uvod u programiranje", 25}, {19, 1, 2020}},  <<==4
    {"Fata Fatic", 8, {1, "Uvod u programiranje", 25}, {19, 1, 2020}},
    {"Mujo Suljic", 7, {2, "Inzenjerska fizika", 10}, {11, 1, 2020}}, <<==3
    {"Mujo Suljic", 10, {3, "Inzenjerska matematika", 6}, {1, 9, 2020}} }; <<< = 4

必须去掉第3行

 {"Mujo Suljic", 7, {2, "Inzenjerska fizika", 10}, {11, 1, 2020}},

但是在你的'comment'中你说

printf("\nAT2: We must not observe the same student more than once\n");

答案显示您必须多次显示同一个学生。

我认为你可以修改代码,现在你发现你误解了赋值的逻辑


你也犯了一些地方没有从数组开头开始的错误

double credits(struct Grade arr[], int n, int i) {
    int j;
    double sum = arr[i].subject.ects;
    for (j = i + 1; j < n; j++)
        if (strcmp(arr[j].namesurname, arr[i].namesurname) == 0)
            sum += arr[j].subject.ects;
    return sum;
}

我加了

double credits(struct Grade arr[], int n, int i) {
    int j;
    double sum = arr[i].subject.ects;
    for (j = i + 1; j < n; j++)
        if (strcmp(arr[j].namesurname, arr[i].namesurname) == 0)
            sum += arr[j].subject.ects;
    printf("credits = %f for %s\n", sum, arr[i].namesurname); <<<<==
    return sum;
}

对于 AT3 我得到

AT3: Multiple successive ejections
credits = 66.000000 for Mujo Suljic
credits = 25.000000 for Fata Fatic

不正确

法塔有 50 个。

这是因为你开始了一半。我认为你在最小计算中犯了同样的错误

最后你有一些非常简单的错误

我留给你找出问题所在(暗示你对 'min' 是什么感到困惑,加上其他 2 个错误)

int find_min(struct Grade arr[], int n, int i) {
    int j,
        min = 10;// check_digits(arr[i].date.day, arr[i].date.month, arr[i].date.year);
    int minIdx = -1;
    for (j = i ; j < n; j++)
        if (strcmp(arr[j].namesurname, arr[i].namesurname) == 0)
            if (check_digits(arr[j].date.day, arr[j].date.month, arr[j].date.year) <
                min)
                minIdx = j;
    return minIdx;
}