当前位置: 首页 > article >正文

谭浩强C语言程序设计(5) 9章

1、统计三个候选人的票数

#include <cstdio>  // 引入标准输入输出库
#include <cstring> // 引入字符串处理库,用于 strcmp 函数
#define N 10       // 定义一个宏常量 N,表示数组的最大长度

// 定义一个结构体 Person,用于存储姓名和计数
struct Person {
    char name[N]; // 名字字符串
    int count;    // 计数器,用于记录名字出现的次数
};

int main() {
    // 初始化一个 Person 结构体数组,包含 3 个预设人员
    Person person[3] = {
        {"zs", 0}, // 第一个人
        {"ls", 0}, // 第二个人
        {"ww", 0}  // 第三个人
    };

    // 定义一个二维数组 names,用于存储用户输入的名字
    char names[N][N];

    // 从用户输入读取 10 个名字并存储到 names 数组中
    for (int i = 0; i < N; ++i) {
        printf("input the name%d:", i + 1); // 提示用户输入第 i 个名字
        scanf("%s", names[i]);             // 将用户输入的名字存储到 names[i]
    }

    // 遍历输入的名字数组,统计每个名字出现的次数
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < 3; ++j) { // 遍历预设的 Person 结构体数组
            if (strcmp(person[j].name, names[i]) == 0) { // 比较当前名字与预设名字是否相同
                person[j].count++; // 如果相同,计数器加 1
            }
        }
    }

    // 输出统计结果
    printf("result:\n");
    for (int i = 0; i < 3; ++i) {
        printf("%s:%d\n", person[i].name, person[i].count); // 输出每个名字及其出现次数
    }

    return 0; // 程序正常结束
}

2、从小到大按照成绩输出n个学生的信息

#include <cstdio>  // 引入标准输入输出库
#include <cstring> // 引入字符串处理库
#define M 3        // 定义常量 M,表示学生数量
#define N 10       // 定义常量 N,表示字符数组的最大长度

// 定义一个结构体 Student,用于存储学生的信息
struct Student {
    int id;        // 学生的学号
    char name[N];  // 学生的姓名
    float score;   // 学生的成绩
};

// 折半插入排序函数,按照学生成绩从大到小排序
void sort(Student student[]) {
    int low, high, mid; // 定义折半查找的变量
    Student temp;       // 定义一个临时变量,用于存储当前需要插入的学生信息

    // 外层循环,从第二个学生开始,逐个进行插入排序
    for (int i = 1; i < M; ++i) {
        low = 0;                // 初始化 low 为有序子序列的起始索引
        high = i - 1;           // 初始化 high 为有序子序列的末尾索引
        temp = student[i];      // 将当前学生信息存储到临时变量 temp 中

        // 使用折半查找确定当前学生在有序子序列中的插入位置
        while (low <= high) {
            mid = (low + high) / 2; // 计算中间位置索引
            if (student[mid].score > temp.score) {
                low = mid + 1;      // 如果中间位置的学生成绩大于当前学生成绩,调整 low
            } else {
                high = mid - 1;     // 如果中间位置的学生成绩小于等于当前学生成绩,调整 high
            }
        }

        // 将有序子序列中从插入位置到当前位置的学生向后移动一位,为当前学生腾出空间
        for (int j = i - 1; j >= low; --j) {
            student[j + 1] = student[j];
        }

        // 将当前学生插入到正确的位置
        student[low] = temp;
    }
}

int main() {
    Student student[M]; // 定义一个 Student 类型的数组,用于存储 M 个学生的信息

    // 从用户输入读取 M 个学生的信息
    for (int i = 0; i < M; ++i) {
        printf("input the No.%d student info(id,name,score):\n", i + 1); // 提示用户输入第 i+1 个学生信息
        scanf("%d %s %f", &student[i].id, student[i].name, &student[i].score); // 读取学生信息并存储到数组中
    }

    sort(student); // 调用排序函数,对学生数组进行排序

    // 输出排序后的结果
    printf("result:\n");
    for (int i = 0; i < M; ++i) {
        printf("%d %s %3.2f\n", student[i].id, student[i].name, student[i].score); // 输出每个学生的学号、姓名和成绩
    }

    return 0; // 程序正常结束
}

3、通过指向结构体变量的指针输出结构体变量成员的信息

#include <cstdio>
// 引入C++标准输入输出库,用于使用printf等函数

struct Student {
    int id; // 学生的学号
    char name[10]; // 学生的姓名,最多9个字符(第10个字符用于存储字符串结束符)
    float score; // 学生的成绩
};

int main() {
    // 定义一个包含3个学生信息的数组
    Student student[3] = {
        {1, "zs", 12},   // 第一个学生:学号1,名字"zs",成绩12
        {2, "lisi", 90}, // 第二个学生:学号2,名字"lisi",成绩90
        {3, "ww", 89}    // 第三个学生:学号3,名字"ww",成绩89
    };

    // 遍历学生数组
    for (Student* p = student; p < student + 3; p++) {
        // 使用指针p遍历数组student,student+3表示数组最后一个元素的下一个位置,作为结束条件

        // 格式化输出学生信息
        printf("%d-%s-%3.2f\n", p->id, p->name, p->score);
        // 格式解释:
        // %d:输出整数(学生学号)
        // %s:输出字符串(学生姓名)
        // %3.2f:输出浮点数,保留两位小数
        // \n:换行符,用于换行
    }

    return 0; // 主函数返回值,表示程序成功结束
}

4、使用结构体变量或者结构体指针作为参数实现下面函数

1、输入N个学生信息,求各学生的平均成绩。

2、求平均分最高的学生的信息。

3、 输出总成绩最高的学生的信息

#include <cstdio>
#define N 3  // 学生数量

struct Student {
    int id;
    char name[10];
    float score[3];
    float average;
    float total;  //总成绩
};

void input(Student* p) {
    for (int i = 0; i < N; ++i) {
        float sum = 0;
        printf("input the No%d's id:\n", i + 1);
        scanf("%d", &p[i].id);
        printf("input the No%d's name:\n", i + 1);
        scanf("%9s", p[i].name); // 限制输入长度为9,避免溢出
        printf("input the No%d's score:\n", i + 1);
        for (int j = 0; j < 3; ++j) {
            scanf("%f", &p[i].score[j]);
            sum += p[i].score[j];
        }
        p[i].total = sum;
        p[i].average = sum / 3;
    }
}

Student max(Student* p) {
    Student max_student = p[0];
    for (int i = 1; i < N; ++i) {
        if (max_student.average < p[i].average) {
            max_student = p[i];
        }
    }
    return max_student;
}

void print(Student* p){
    Student max = p[0];
    for (int i = 0; i < N; ++i) {
        if (max.total < p[i].total){
            max = p[i];
        }
    }
    printf("The max student's info:\n");
    printf("id:%d\n", max.id);
    printf("name:%s\n", max.name);
    printf("score: ");
    for (int i = 0; i < 3; ++i) {
        printf("%.2f", max.score[i]);
        if (i < 2) printf(" "); // 添加空格分隔成绩
    }
    printf("\naverage:%.2f\n", max.average);
    printf("\ntotal:%.2f\n", max.total);
}

int main() {
    Student student[N];
    Student* p = student;
    input(p);
    Student s = max(p);
    printf("the max average student's info:\n");
    printf("id:%d\n", s.id);
    printf("name:%s\n", s.name);
    printf("score: ");
    for (int i = 0; i < 3; ++i) {
        printf("%.2f", s.score[i]);
        if (i < 2) printf(" "); // 添加空格分隔成绩
    }
    printf("\naverage:%.2f\n", s.average);
    printf("\ntotal:%.2f\n", s.total);
    print(p);
    return 0;
}

5、创建动态单链表存储N个学生的成绩

#include <cstdio>
#include <cstdlib>
#define N 3

// 定义学生结构体
typedef struct Student {
    int num;                // 学号
    float score;            // 分数
    struct Student* next;   // 指向下一个节点的指针(自引用指针)
} Student;

/*
 * 初始化带头结点的单链表
 * 参数:head - 二级指针,用于修改主函数中的头指针
 * 功能:创建头结点,并使头指针指向该头结点
 */
void init(Student** head) {
    *head = (Student*)malloc(sizeof(Student)); // 为头结点分配内存
    if (*head == NULL) {                       // 内存分配失败处理
        printf("内存分配失败");
        exit(1);                               // 终止程序
    }
    (**head).next = NULL;                      // 头结点的next初始化为NULL
}

/*
 * 向链表中插入数据(尾插法)
 * 参数:head - 二级指针,用于获取头结点位置
 * 功能:创建N个新节点,并将它们依次链接到链表尾部
 */
void insert(Student** head) {
    int n = 0;
    int num = 0;
    float score = 0;
    Student* tail = *head; // tail指针初始指向头结点(此时链表为空)

    while (n != N) {
        // 创建新节点并初始化数据
        Student* newNode = (Student*)malloc(sizeof(Student));
        if (newNode == NULL) {
            printf("内存分配失败");
            exit(1);
        }
        printf("input the %d student info:\n", n + 1);
        printf("num is:\n");
        scanf("%d", &num);
        printf("score is:\n");
        scanf("%f", &score);

        (*newNode).num = num;
        (*newNode).score = score;
        (*newNode).next = NULL;  // 新节点next初始化为NULL

        // 将新节点链接到链表尾部
        (*tail).next = newNode;  // 当前尾节点的next指向新节点
        tail = newNode;          // tail指针移动到新节点(更新尾指针位置)

        n++;
    }
}

/*
 * 打印链表数据
 * 参数:head - 链表头指针
 * 功能:遍历链表并打印每个节点的数据
 */
void printList(Student* head) {
    Student* p = (*head).next; // 跳过头结点,从第一个数据节点开始遍历
    while (p != NULL) {
        printf("Num: %d, Score: %.2f\n", (*p).num, (*p).score);
        p = (*p).next;         // 指针移动到下一个节点
    }
}

int main() {
    // 初始化单链表
    Student* head;           // 头指针声明
    init(&head);             // 传递头指针的地址以初始化链表

    // 插入数据(N个学生信息)
    insert(&head);           // 传递头指针的地址以访问头结点

    // 打印链表
    printList(head);

    return 0;
}

1、初始化函数init

  • *head:解引用 head,得到的是主函数中 Student* head 这个指针的值,也就是头结点的地址。
  • **head:再次解引用 *head,得到的是头结点本身(即 Student 结构体)

 6、若干个教师和学生,老师和学生的数据基本相同但是老师有个数据是职务,学生有个数据是班级。使用共同体类型输出教师和学生的信息。

#include <cstdio>
#define N 2

struct Person{
    int num;
    char name[10];
    char gender;
    char job;
    union Category{
        int clazz;
        char position[10];
    }Category;
}Person[N];

int main(){
   int i ;
    for (int j = 0; j < N; ++j) {
        printf("input the %d person's info:\n",j+1);
        scanf("%d %s %c %c",&Person[j].num,Person[j].name,&Person[j].gender,&Person[j].job);
        if (Person[j].job == 's'){
            scanf("%d",&Person[j].Category.clazz);
        }else if (Person[j].job == 't'){
            scanf("%s",Person[j].Category.position);
        } else{
            puts("error!!!");
        }
    }
    printf("\n");
    for (int j = 0; j < N; ++j) {
        if (Person[j].job == 's'){
            printf("student's info:\n");
            printf("num:%d name:%s gender:%c job:%c class:%d\n",Person[j].num,Person[j].name,Person[j].gender,Person[j].job,Person[j].Category.clazz);
        } else if (Person[j].job == 't'){
            printf("teacher's info:\n");
            printf("num:%d name:%s gender:%c job:%c prof:%s\n",Person[j].num,Person[j].name,Person[j].gender,Person[j].job,Person[j].Category.position);
        }
    }
}

 7、使用结构体计算该日是本年中的第几天

#include <cstdio>

// 定义一个结构体 YMD,用于存储年、月、日
struct YMD {
    int year;  // 年份
    int month; // 月份
    int days;  // 日期
};

// 用于计算从年初到指定日期的总天数
// 参数通过值传递,确保函数不会修改原始数据
int compute(YMD ymd) {
    int month = ymd.month - 1;  // 当前月份的前一个月(已完成的完整月份)
    bool flag = false;          // 用于标记是否为闰年
    int sum = 0;                // 用于累加总天数

    // 判断是否为闰年
    // 闰年的条件:能被4整除但不能被100整除,或者能被400整除
    if ((ymd.year % 4 == 0 && ymd.year % 100 != 0) || (ymd.year % 400 == 0)) {
        flag = true; // 如果是闰年,将其标记为 true
    }

    // 遍历从 1 月到目标月的前一个月,累加每个月的天数
    for (int i = 1; i <= month; ++i) {
        if (i == 1 || i == 3 || i == 5 || i == 7 || i == 8 || i == 10 || i == 12) {
            // 1、3、5、7、8、10、12 月为大月,有 31 天
            sum += 31;
        } else if (i == 2) {
            // 2 月的天数根据是否为闰年而变化
            if (flag) {
                sum += 29; // 闰年时 2 月有 29 天
            } else {
                sum += 28; // 平年时 2 月有 28 天
            }
        } else {
            // 4、6、9、11 月为小月,有 30 天
            sum += 30;
        }
    }

    // 将输入的日期累加到总天数中
    sum += ymd.days;

    return sum; // 返回从年初到指定日期的总天数
}

int main() {
    YMD ymd; // 定义一个 YMD 结构体变量

    // 提示用户输入年份、月份和日期
    printf("input the year, month, days:\n");

    // 读取用户输入的年份、月份和日期
    scanf("%d %d %d", &ymd.year, &ymd.month, &ymd.days);

    // 调用 compute 函数计算总天数
    int sum = compute(ymd);

    // 输出结果
    printf("%d", sum);

    return 0; // 程序结束
}

8、使用结构存储N个学生的信息并输出

#include <cstdio>

#define N 3

struct Student {
    int num;          // 学生学号
    char name[10];    // 学生姓名
    int score[N];     // 学生成绩数组
};

void input(Student student[]) {
    for (int i = 0; i < N; ++i) {
        printf("input the %d's num, name, and %d scores: ", i + 1, N);
        scanf("%d %9s", &student[i].num, student[i].name); // 限制姓名长度为 9
        for (int j = 0; j < N; ++j) {
            scanf("%d", &student[i].score[j]);
        }
    }
}

void output(Student student[]) {
    // 输出表头
    printf("%10s%10s", "Num", "Name");
    for (int j = 0; j < N; ++j) {
        printf("%10s%d", "Score", j + 1);
    }
    printf("\n");

    // 输出学生信息
    for (int i = 0; i < N; ++i) {
        printf("%10d%10s", student[i].num, student[i].name);
        for (int j = 0; j < N; ++j) {
            printf("%10d", student[i].score[j]);
        }
        printf("\n");
    }
}

int main() {
    Student student[N]; // 局部数组
    input(student);
    output(student);

    // 输出所有学生的学号
    printf("\n-------\n");
    for (int i = 0; i < N; ++i) {
        printf("%d ", student[i].num);
    }
    printf("\n");

    return 0;
}

input 函数能够改变数组的值,是因为 C/C++ 中数组作为函数参数时,实际上传递的是数组的指针,而不是数组的副本。 

9、约瑟夫环问题,13个人数到三的淘汰问最后剩下的是谁,使用链表实现

#include <cstdio>
#include <cstdlib>
#define N 13  // 定义链表中节点的总数为 13

struct LNode {
    int num;               // 节点的编号
    struct LNode* next;    // 指向下一个节点的指针
};

// 单链表的初始化
void init(LNode** head) {
    *head = (LNode*)malloc(sizeof(LNode));  // 分配头节点的内存
    if (*head == NULL) {  // 检查内存分配是否成功
        perror("Failed to allocate memory for head");
        exit(EXIT_FAILURE);  // 分配失败时退出程序
    }
    (*head)->next = NULL;  // 初始化头节点的 next 指针为 NULL
}

// 插入 13 个数据并形成循环链表
void input(LNode** head) {
    LNode* tail = *head;  // 用 tail 指针跟踪链表的尾部
    for (int j = 1; j <= N; ++j) {  // 循环插入 13 个节点
        LNode* newNode = (LNode*)malloc(sizeof(LNode));  // 分配新节点的内存
        if (newNode == NULL) {  // 检查内存分配是否成功
            perror("Failed to allocate memory for new node");
            exit(EXIT_FAILURE);  // 分配失败时退出程序
        }
        newNode->num = j;  // 设置新节点的编号为 j
        newNode->next = NULL;  // 初始化新节点的 next 指针为 NULL
        tail->next = newNode;  // 将新节点连接到链表尾部
        tail = newNode;  // 更新 tail 指针到新节点
    }
    // 将最后一个节点的 next 指向头节点的下一个节点,形成循环链表
    tail->next = (*head)->next;
}

// 模拟约瑟夫问题
void play(LNode** L) {
    LNode* p = *L;  // p 指针指向头节点
    LNode* q = p->next;  // q 指针指向第一个节点
    int count = 1;  // 报数计数器
    int leave = N;  // 剩余节点数
    printf("Deleting node:");  // 打印删除的节点编号

    while (leave > 1) {  // 当剩余节点数大于 1 时继续循环
        if (count == 3) {  // 当报数到 3 时
            LNode* temp = q;  // 保存要删除的节点
            printf("%d ", temp->num);  // 打印要删除的节点编号
            p->next = q->next;  // 跳过当前节点
            free(temp);  // 释放要删除的节点内存
            q = p->next;  // 更新 q 指针到下一个节点
            count = 1;  // 重置计数器
            leave--;  // 减少剩余节点数

            // 如果只剩一个节点,退出循环
            if (leave == 1) break;
        } else {
            p = p->next;  // p 指针移动到下一个节点
            q = q->next;  // q 指针移动到下一个节点
            count++;  // 计数器加 1
        }
    }

    // 最后只剩一个节点时,确保头节点的 next 指针指向该节点
    (*L)->next = q;
}

// 输出最后剩下的人
void output(LNode** head) {
    LNode* p = (*head)->next;  // p 指针指向最后一个节点
    if (p != NULL) {  // 如果 p 不为空
        printf("\nThe last one is: %d\n", p->num);  // 打印最后一个节点的编号
    } else {
        printf("Error: No remaining nodes.\n");  // 如果无节点,输出错误信息
    }
}

// 释放链表
void freeList(LNode** head) {
    if (*head == NULL) return;  // 如果头节点为空,直接返回

    // 断开头节点与数据节点的连接
    LNode* dataNode = (*head)->next;
    (*head)->next = NULL;

    // 释放循环链表中的所有数据节点
    while (dataNode) {  // 当还有数据节点时
        LNode* temp = dataNode;  // 保存当前节点
        dataNode = dataNode->next;  // 移动到下一个节点
        free(temp);  // 释放当前节点
    }

    // 释放头节点
    free(*head);
    *head = NULL;  // 将头指针置为空
}

int main() {
    LNode* L;  // 定义链表头指针
    init(&L);  // 初始化链表
    input(&L);  // 插入节点并形成循环链表
    play(&L);  // 模拟约瑟夫问题
    output(&L);  // 输出最后剩下的人
    freeList(&L);  // 释放链表
    return 0;  // 程序结束
}

 10、AB两个链表每个结点存储的是学生的成绩要求两个链表合并并按照学号升序输出

#include <cstdio>
#include <cstdlib>

struct Student {
    int num;       // 学号
    int score;     // 成绩
    struct Student* next;  // 指向下一个节点的指针
};

// 初始化两个链表
void init(Student** stuA, Student** stuB) {
    *stuA = (Student*)malloc(sizeof(Student)); // 分配头节点的内存
    *stuB = (Student*)malloc(sizeof(Student)); // 分配头节点的内存
    if (*stuA == NULL || *stuB == NULL) {
        printf("初始化失败,内存分配错误。\n");
        exit(EXIT_FAILURE);
    }
    (*stuA)->next = NULL; // 初始化头节点的 next 指针为 NULL
    (*stuB)->next = NULL; // 初始化头节点的 next 指针为 NULL
}

// 创建链表
int create(Student** stu) {
    Student* tail = *stu; // 尾指针,用于跟踪链表的尾部
    int num = 0, score = 0, n = 0; // 学号、成绩和计数器
    while (1) {
        Student* newNode = (Student*)malloc(sizeof(Student)); // 分配新节点的内存
        if (newNode == NULL) {
            printf("节点创建失败,内存分配错误。\n");
            exit(EXIT_FAILURE);
        }

        printf("请输入第%d个学生的学号和成绩(输入999结束):\n", n + 1);
        if (scanf("%d %d", &num, &score) != 2) {
            printf("输入错误,程序终止。\n");
            exit(EXIT_FAILURE);
        }

        if (num == 999) {
            free(newNode); // 如果用户输入 999,释放未使用的节点
            break;
        }

        newNode->num = num; // 设置新节点的学号
        newNode->score = score; // 设置新节点的成绩
        newNode->next = NULL; // 初始化新节点的 next 指针为 NULL

        tail->next = newNode; // 将新节点连接到链表尾部
        tail = newNode; // 更新尾指针到新节点
        n++; // 计数器加 1
    }
    return n; // 返回链表的长度
}

// 打印链表
void print(Student** stu) {
    Student* p = (*stu)->next; // p 指针指向链表的第一个节点
    printf("链表内容:\n");
    while (p != NULL) { // 遍历链表
        printf("学号:%d,成绩:%d\n", p->num, p->score); // 打印当前节点的数据
        p = p->next; // 移动到下一个节点
    }
}

// 合并两个链表
void concat(Student** stuA, Student** stuB) {
    Student* pa = (*stuA)->next; // pa 指针指向链表 A 的第一个节点
    Student* pb = (*stuB)->next; // pb 指针指向链表 B 的第一个节点
    Student* concatHead = NULL;  // 合并后链表的头指针
    Student** current = &concatHead;  // 当前插入位置的指针

    // 合并两个链表
    while (pa != NULL && pb != NULL) {
        if (pa->num < pb->num) { // 如果链表 A 的当前节点学号小于链表 B 的当前节点学号
            *current = pa; // 将链表 A 的当前节点连接到合并后的链表
            pa = pa->next; // 移动 pa 指针到链表 A 的下一个节点
        } else {
            *current = pb; // 将链表 B 的当前节点连接到合并后的链表
            pb = pb->next; // 移动 pb 指针到链表 B 的下一个节点
        }
        current = &((*current)->next); // 更新当前插入位置的指针
    }

    // 如果链表 A 或链表 B 中还有剩余节点,将剩余节点连接到合并后的链表
    *current = (pa != NULL) ? pa : pb;

    // 更新链表 A 的头指针,使其指向合并后的链表
    (*stuA)->next = concatHead;
}

// 释放链表的内存
void freeList(Student** stu) {
    Student* p = (*stu)->next; // p 指针指向链表的第一个节点
    while (p != NULL) { // 遍历链表
        Student* temp = p; // 保存当前节点
        p = p->next; // 移动到下一个节点
        free(temp); // 释放当前节点的内存
    }
    free(*stu); // 释放头节点的内存
}

int main() {
    Student* stuA, *stuB; // 定义两个链表的头指针
    init(&stuA, &stuB); // 初始化链表

    printf("创建链表 A:\n");
    int lenA = create(&stuA); // 创建链表 A
    printf("创建链表 B:\n");
    int lenB = create(&stuB); // 创建链表 B

    printf("合并前链表 A:\n");
    print(&stuA); // 打印链表 A 的内容
    printf("合并前链表 B:\n");
    print(&stuB); // 打印链表 B 的内容

    concat(&stuA, &stuB); // 合并链表 A 和 B

    printf("合并后链表 A:\n");
    print(&stuA); // 打印合并后的链表 A

    // 释放链表的内存
    freeList(&stuA);
    freeList(&stuB);

    return 0; // 程序结束
}
D:\C\code\test\fileA.exe
Creating list A:
Enter the ID and score for student 1 (enter 999 to exit):
1 45
Enter the ID and score for student 2 (enter 999 to exit):
3 45
Enter the ID and score for student 3 (enter 999 to exit):
5 33
Enter the ID and score for student 4 (enter 999 to exit):
7 90
Enter the ID and score for student 5 (enter 999 to exit):
999 999
Creating list B:
Enter the ID and score for student 1 (enter 999 to exit):
2 23
Enter the ID and score for student 2 (enter 999 to exit):
4 11
Enter the ID and score for student 3 (enter 999 to exit):
6 12
Enter the ID and score for student 4 (enter 999 to exit):
999 999
List A before concatenation:
List contents:
ID: 1, Score: 45
ID: 3, Score: 45
ID: 5, Score: 33
ID: 7, Score: 90
List B before concatenation:
List contents:
ID: 2, Score: 23
ID: 4, Score: 11
ID: 6, Score: 12
List A after concatenation:
List contents:
ID: 1, Score: 45
ID: 2, Score: 23
ID: 3, Score: 45
ID: 4, Score: 11
ID: 5, Score: 33
ID: 6, Score: 12
ID: 7, Score: 90

11、ab两个链表,节点中包含学号姓名,从a链表中删除与b链表中相同学号的节点

#include <cstdio>
#include <cstdlib>

struct Student {
    int num;       // 学号
    int score;     // 成绩
    struct Student* next;  // 指向下一个节点的指针
};

// 初始化两个链表
void init(Student** stuA, Student** stuB) {
    *stuA = (struct Student*)malloc(sizeof(Student)); // 分配头节点的内存
    *stuB = (struct Student*)malloc(sizeof(Student)); // 分配头节点的内存
    if (*stuA == NULL || *stuB == NULL) {
        printf("初始化失败,内存分配错误。\n");
        exit(EXIT_FAILURE);
    }
    (*stuA)->next = NULL; // 初始化头节点的 next 指针为 NULL
    (*stuB)->next = NULL; // 初始化头节点的 next 指针为 NULL
}

// 创建链表
void create(Student** stu) {
    Student* tail = *stu; // 尾指针,用于跟踪链表的尾部
    int num = 0, score = 0, n = 0; // 学号、成绩和计数器
    while (true) {
        Student* newNode = (struct Student*)malloc(sizeof(Student)); // 分配新节点的内存
        if (newNode == NULL) {
            printf("error。\n");
            exit(EXIT_FAILURE);
        }

        printf("Please enter the student ID and score for the %dth student (Enter 999 to finish):\n", n + 1);
        if (scanf("%d %d", &num, &score) != 2) {
            printf("输入错误,程序终止。\n");
            exit(EXIT_FAILURE);
        }

        if (num == 999) {
            free(newNode); // 如果用户输入 999,释放未使用的节点
            break;
        }

        newNode->num = num; // 设置新节点的学号
        newNode->score = score; // 设置新节点的成绩
        newNode->next = NULL; // 初始化新节点的 next 指针为 NULL

        tail->next = newNode; // 将新节点连接到链表尾部
        tail = newNode; // 更新尾指针到新节点
        n++;
    }
}

// 打印链表
void print(Student** stu) {
    Student* p = (*stu)->next; // p 指针指向链表的第一个节点
    printf("contents\n");
    while (p != NULL) { // 遍历链表
        printf("num:%d,score:%d\n", p->num, p->score); // 打印当前节点的数据
        p = p->next; // 移动到下一个节点
    }
}

// 删除相同的节点
void del(Student** stuA, Student** stuB) {
    Student* pa = *stuA;
    Student* temp;
    Student* pb = *stuB;
    while (pb) {
        pa = *stuA; // 重置pa到链表A的头节点
        while (pa->next) {
            if (pa->next->num == pb->num) {
                temp = pa->next;
                pa->next = temp->next;
                free(temp);
            } else {
                pa = pa->next;
            }
        }
        pb = pb->next;
    }
}

// 释放链表的内存
void freeList(Student** stu) {
    Student* p = (*stu)->next; // p 指针指向链表的第一个节点
    while (p != NULL) { // 遍历链表
        Student* temp = p; // 保存当前节点
        p = p->next; // 移动到下一个节点
        free(temp); // 释放当前节点的内存
    }
    free(*stu); // 释放头节点的内存
}

int main() {
    Student* stuA, *stuB; // 定义两个链表的头指针
    init(&stuA, &stuB); // 初始化链表

    printf("create A\n");
    create(&stuA); // 创建链表 A
    printf("create B\n");
    create(&stuB); // 创建链表 B


    del(&stuA, &stuB); // 在a中删除和b表相同的节点


    print(&stuA); // 打印合并后的链表 A

    // 释放链表的内存
    freeList(&stuA);
    freeList(&stuB);

    return 0; // 程序结束
}


http://www.kler.cn/a/546279.html

相关文章:

  • 站群服务器和普通服务器有哪些不同之处?
  • Node.js 工具模块
  • 深入浅出理解HBase:大数据时代的“超级仓库”
  • 在 CentOS 系统中配置交换空间(Swap)解决内存不足
  • 《计算机视觉》——角点检测和特征提取sift
  • (萌新入门)如何从起步阶段开始学习STM32 —— 0.碎碎念
  • 【前端框架】Vue3 面试题深度解析
  • 【Elasticsearch源码解读】代码包结构概述
  • 怎么理解 Spring Boot 的约定优于配置 ?
  • C语言如何实现面向对象?——从结构体到自由函数的思考
  • 探索高通骁龙游戏超分辨率技术:移动游戏的未来
  • LeetCode 热门100题-合并区间
  • AWS Database Migration Service
  • 【MySQL】 基本查询(上)
  • 可可泛基因组-文献精读112
  • 【TI C2000】F28002x的系统延时、GPIO配置及SCI(UART)串口发送、接收
  • 数仓:核心概念,数仓系统(ETL,数仓分层,数仓建模),数仓建模方法(星型模型,雪花模型,星座模型)和步骤
  • 无人机遥感在智慧农业信息提取的综合态势,包含:无人机平台的性能、机载传感器指标、地面传感器应用、农林遥感光谱指数、农林光谱建模方法等
  • ReactiveSwift模拟登录功能
  • 单元测试、系统测试、集成测试知识详解