谭浩强c语言程序设计 第九章结构体

第九章 结构体

文章目录

例9.1 把一个学生的信息,包括学号、姓名、性别、地址放在一个结构体变量中,然后输出这个学生的信息
#include<stdio.h>
int main(){
    struct Student{
        long int num;
        char name[20];
        char sex;
        char addr[20];
    }a={10101,"sxy",'M',"123 beijing"};
    printf("No.:%ld\nname:%s\nsex:%c\naddress:%s\n",a.num,a.name,a.sex,a.addr);
    return 0;
}
例9.2 输入两个学生的学号姓名和成绩,输出成绩较高的学生的学号、姓名和成绩

解题思路:定义两个结构相同的结构体变量,分别输入,比较成绩

#include<stdio.h>
int main(){
    struct Student{
        int num;
        char name[20];
        float score[20];
    }student1,student2;
    scanf("%d%s%f",&student1.num,student1.name,&student1.score); 
    scanf("%d%s%f",&student2.num,student2.name,&student2.score); 
    if(student1.score>student2.score)
    	printf("%d         %s          %6.2f\n",student1.num,student1.name,student1.score);
    else if(student1.score<student2.score)
    	printf("%d         %s          %6.2f\n",student2.num,student2.name,student2.score);
    else{
    	printf("%d         %s          %6.2f\n",student1.num,student1.name,student1.score);
    	printf("%d         %s          %6.2f\n",student2.num,student2.name,student2.score);
	}
    return 0;
}
例9.3 有三个候选人,每个选民只能投票选一人,要求编一个统计选票的程序,先后输入备选人的名字,最后输出个人得票结果

解题思路:设一个结构体数组,数组包含3个元素,每个元素中的信息应包含姓名和得票数。输入备选人的名字,然后与数组元素中的姓名成员比较,如果相同,就给这个元素中的得票数成员值加一。最后输出所有元素信息。

#include<stdio.h>
#include<string.h>
struct 	person{
	char name[20];
	int count;
}leader[3]={"li",0,"zhang",0,"sun",0};
int main(){
  int i,j;
  char leader_name[20];
  for(i=1;i<=10;i++){
  	scanf("%s",leader_name);
  	for(j=0;j<3;j++)
  		if(strcmp(leader_name,leader[j].name)==0)
  			leader[j].count++;
  }
  printf("\nRestult:\n");
  for(i=0;i<3;i++)
  	printf("%5s:%d\n",leader[i].name,leader[i].count);
	return 0;
}
例9.4 有n个学生的信息(学号、姓名、成绩),要求按照成绩的高低顺序输出各学生的信息。

解题思路:用结构体数组存放n个学生信息,采用选择法对各元素进行排序

#include<stdio.h>
struct 	student{
	int num;
	char name[20];
	float score;
};
int main(){
	struct student stu[5]={{10101,"sxy",78},{10102,"shz",88},{10103,"cgs",99},{10104,"wbd",100},{10105,"yyy",20}};
  struct student temp;
  const int n=5;
  int i,j,k;
  for(i=0;i<n-1;i++){
  	k=i;
  	for(j=i+1;j<n;j++)
  		if(stu[j].score>stu[k].score) k=j;
  		temp=stu[k];stu[k]=stu[i];stu[i]=temp;
  }
  for(i=0;i<n;i++)
  	printf("%6d%8s%6.2f\n",stu[i].num,stu[i].name,stu[i].score);
	return 0;
}
例9.5 通过指向结构体变量的指针输出结构体变量中成员信息
#include<stdio.h>
#include<string.h> 

// 定义学生结构体
struct Student {
    long num;              // 学号
    char name[20];         // 姓名
    char sex;              // 性别
    float score;           // 成绩
};

int main() {
    struct Student stu_1;  // 定义一个结构体变量
    struct Student *p;     // 定义一个结构体指针
    p = &stu_1;            // 指针指向结构体变量 stu_1

    // 给结构体成员赋值
    stu_1.num = 10101;
    strcpy(stu_1.name, "li ming");
    stu_1.sex = 'M';
    stu_1.score = 89.5;

    // 使用直接访问结构体变量的方式输出
    printf("Using struct variable:\n");
    printf("no.:%ld\nname:%s\nsex:%c\nscore:%5.1f\n", stu_1.num, stu_1.name, stu_1.sex, stu_1.score);

    // 使用指针访问结构体成员的方式输出
    printf("\nUsing pointer to struct:\n");
    printf("no.:%ld\nname:%s\nsex:%c\nscore:%5.1f\n", p->num, p->name, p->sex, p->score);

    return 0;
}

例9.6 有3个学生的信息,放在结构体数组中,要求输出全部学生的信息。

解题思路:用指向结构体变量的指针来处理

#include<stdio.h>
#define N 3

// 定义学生结构体
struct Student {
    int num;              // 学号
    char name[20];         // 姓名
    char sex;              // 性别
    int age;               // 年龄
};

// 初始化学生数据
struct Student stu[N] = {
    {10101, "sxy", 'M', 78},
    {10102, "shz", 'F', 88},
    {10103, "cgs", 'M', 99}
};

int main() {
    struct Student *p;
    
    // 打印表头
    printf("No.    Name                Sex   Age\n");
    
    // 遍历学生数组并打印每个学生的信息
    for(p = stu; p < stu + N; p++) {
        printf("%5d %-20s %2c %4d\n", p->num, p->name, p->sex, p->age);
    }

    return 0;
}

例9.7 有n个结构体变量,内含学生学号、姓名和3门课程的成绩。要求输出平均成绩最高的学生的信息(包括学号、姓名、3门课程成绩和平均成绩)

解题思路:input函数来输入数据和求各学生平均成绩,max函数来找平均成绩最高的学生。用print函数来输出成绩最高学生在信息

#include <stdio.h>
#define N 3

// 定义学生结构体
struct Student {
    int num;              // 学号
    char name[20];        // 姓名
    float score[3];       // 三门课程的成绩
    float aver;           // 平均成绩
};

// 函数声明
void input(struct Student stu[]);
struct Student max(struct Student stu[]);
void print(struct Student stu);

// 主函数
int main() {
    struct Student stu[N], *p = stu;
    
    // 输入学生信息
    input(p);
    
    // 打印成绩最高的学生信息
    print(max(p));
    
    return 0;
}

// 输入学生信息并计算平均分
void input(struct Student stu[]) {
    int i, j;
    for(i = 0; i < N; i++) {
        printf("请输入第 %d 个学生的学号、姓名和三门课成绩:\n", i + 1);
        scanf("%d %s", &stu[i].num, stu[i].name);
        
        stu[i].aver = 0;
        for(j = 0; j < 3; j++) {
            scanf("%f", &stu[i].score[j]);  // 输入每门课程成绩
            stu[i].aver += stu[i].score[j]; // 计算总成绩
        }
        stu[i].aver /= 3;  // 计算平均成绩
    }
}

// 找到平均成绩最高的学生
struct Student max(struct Student stu[]) {
    int i, maxIndex = 0;
    for(i = 1; i < N; i++) {
        if(stu[i].aver > stu[maxIndex].aver) {
            maxIndex = i;
        }
    }
    return stu[maxIndex];  // 返回成绩最高的学生
}

// 打印成绩最高的学生信息
void print(struct Student stu) {
    printf("成绩最高的学生是:\n");
    printf("学号:%d\n姓名:%s\n", stu.num, stu.name);
    printf("三门课成绩:%.1f, %.1f, %.1f\n", stu.score[0], stu.score[1], stu.score[2]);
    printf("平均成绩:%.2f\n", stu.aver);
}

例9.8建立一个如图9.9的简单链表,它由3个学生数据的结点组成,要求输出各节点中数据。

解题思路:

#include<stdio.h>
#include<stdlib.h>

// 定义学生结构体
struct Student {
    int num;              // 学号
    float score;          // 成绩
    struct Student *next; // 指向下一个学生节点的指针
};

// 打印学生信息的函数
void print(struct Student* head) {
    struct Student *p = head;  // 初始化指针为头节点
    while(p != NULL) {         // 遍历链表直到最后一个节点
        printf("%d %.1f\n", p->num, p->score);  // 打印学生学号和成绩
        p = p->next;          // 指针指向下一个节点
    }
}

// 主函数
int main() {
    // 定义三个学生节点
    struct Student a, b, c;

    // 初始化学生信息
    a.num = 10101; a.score = 89.5;
    b.num = 10103; b.score = 90.0;
    c.num = 10107; c.score = 85.0;

    // 设置链表关系
    a.next = &b;
    b.next = &c;
    c.next = NULL;

    // 打印链表
    print(&a);

    return 0;
}

例9.9 写一函数建立由3名学生数据的单项动态链表
#include<stdio.h>
#include<stdlib.h>
#define len sizeof(struct Student)
// 定义学生结构体
struct Student {
    long num;              // 学号
    float score;           // 成绩
    struct student *next;  // 指向下一个学生节点的指针
};

int n = 0;  // 初始化学生数量为0

// 打印学生信息的函数
struct Student*creat(void) {
    struct student *head;
    struct student *p1,*p2;
    p1=p2=(struct Student *)malloc(len);
    scanf("%ld,%f",&p1->num,&p1->score);
    head=NULL;
    while(p1->num!=0){
    	n=n+1;
    	if(n==1) head=p1;
    	else p2->next=p2;
    	p2=p1;
    	p1=(struct Student *)malloc(len);
    	scanf("%ld,%f",&p1->num,&p1->score);
	}
	p2->next=null;
	return(head);
   
}

// 例子:创建一个简单的链表并打印
int main() {
    struct student *pt;
    pt=creat();
    printf("\nnum:%ld\nscore:%5.1f\n",pt->num,pt->score);
    return 0;
};

例9.10 编写一个输出链表的函数print
#include<stdio.h>
#include<stdlib.h>

// 定义学生结构体
struct student {
    long num;              // 学号
    float score;           // 成绩
    struct student *next;  // 指向下一个学生节点的指针
};

int n = 0;  // 初始化学生数量为0

// 打印学生信息的函数
void print(struct student *head) {
    struct student *p;
    printf("\nNow, these %d records are:\n", n);
    p = head;
    
    // 如果链表非空,则遍历并打印每个学生的学号和成绩
    if (head != NULL) {
        do {
            printf("%ld %5.1f\n", p->num, p->score);  // 输出学号和成绩
            p = p->next;  // 移动到下一个学生节点
        } while (p != NULL);
    } else {
        printf("No records to display.\n");
    }
}

// 例子:创建一个简单的链表并打印
int main() {
    struct student *head, *student1, *student2;
    
    // 动态分配两个学生节点的内存
    student1 = (struct student*)malloc(sizeof(struct student));
    student2 = (struct student*)malloc(sizeof(struct student));
    
    // 初始化学生1的数据
    student1->num = 1001;
    student1->score = 95.0;
    student1->next = student2;  // 学生1指向学生2
    
    // 初始化学生2的数据
    student2->num = 1002;
    student2->score = 87.5;
    student2->next = NULL;  // 学生2是最后一个节点,指向NULL
    
    // 头节点指向第一个学生
    head = student1;
    
    // 设置学生数量
    n = 2;
    
    // 打印链表中的学生信息
    print(head);
    
    // 释放动态分配的内存
    free(student1);
    free(student2);
    
    return 0;
}

例9.11 有若干各人员的数据,其中有学生和教师。学生的数据中包括:姓名、好吗、性别、职业、班级。教师:姓名、号码、性别、职业、职务,要求用同一个表格处理
#include<stdio.h>

// 定义结构体 person,用于保存个人信息
struct {
    int num;               // 编号
    char name[10];         // 姓名
    char sex;              // 性别
    char job;              // 工作类型('s' 表示学生,'t' 表示老师)
    
    // 使用 union 表示不同的类别属性(学生有班级,老师有职位)
    union {
        int clas;          // 学生的班级(整数类型)
        char position[10]; // 老师的职位(字符串类型)
    } category;
} person[2];

int main() {
    int i;
    
    // 输入信息
    for (i = 0; i < 2; i++) {
        printf("请输入数据:\n");
        // 输入编号、姓名、性别、工作类型
        scanf("%d %s %c %c", &person[i].num, person[i].name, &person[i].sex, &person[i].job);
        
        // 根据工作类型,输入学生的班级或老师的职位
        if (person[i].job == 's') {
            printf("请输入班级:\n");
            scanf("%d", &person[i].category.clas);  // 学生的班级是整数类型
        } else if (person[i].job == 't') {
            printf("请输入职位:\n");
            scanf("%s", person[i].category.position);  // 老师的职位是字符串
        } else {
            printf("error! 未知的工作类型\n");
        }
    }

    // 输出学生信息
    printf("\nno.   name       sex   job   class/position\n");
    for (i = 0; i < 2; i++) {
        if (person[i].job == 's') {
            // 输出学生的信息,包括班级
            printf("%-6d%-10s%-6c%-6c%d\n", person[i].num, person[i].name, person[i].sex, person[i].job, person[i].category.clas);
        } else if (person[i].job == 't') {
            // 输出老师的信息,包括职位
            printf("%-6d%-10s%-6c%-6c%s\n", person[i].num, person[i].name, person[i].sex, person[i].job, person[i].category.position);
        }
    }

    return 0;
}

例9.12 口袋里有红黄蓝白黑五种颜色的球若干个,每次从口袋中先后取出3个球,问得到3个不同颜色的球的可能取法,输出每种排列的情况

解题思路:球只能是五种颜色之一,要判断各球是否同色,可以用枚举类型变量处理。

设某次取出的三个球的颜色为ijk,根据题意,ijk分别是五种色球之一,并要求三球颜色各不相同,即i≠j≠k。,可以用穷举法把每种组合都试一下,输出合适的。

#include<stdio.h>
int main() {
    // 定义一个枚举类型 color,包含5种颜色
    enum color { red, yellow, blue, white, black };
    
    // 定义枚举类型的变量 i, j, k 和 pri,分别用于保存不同颜色
    enum color i, j, k, pri;
    
    // 定义用于计数的整数变量 n(用于组合编号)和 loop(用于控制颜色输出)
    int n, loop;
    n = 0;  // 初始化 n 为 0,用来记录组合的数量
    
    // 使用嵌套循环来生成不同的颜色组合
    for (i = red; i <= black; i++)  // 外层循环控制第一个颜色
        for (j = red; j <= black; j++)  // 中间循环控制第二个颜色
            // 确保第二个颜色与第一个颜色不同
            if (i != j) {
                for (k = red; k <= black; k++)  // 内层循环控制第三个颜色
                    // 确保第三个颜色与前两个颜色都不同
                    if ((k != i) && (k != j)) {
                        n = n + 1;  // 每生成一个有效组合,n 递增
                        
                        // 打印当前组合的编号
                        printf("%-4d", n);
                        
                        // 通过 loop 控制每个位置上颜色的输出
                        for (loop = 1; loop <= 3; loop++) {
                            switch (loop) {
                                case 1: pri = i; break;  // 第一个位置颜色为 i
                                case 2: pri = j; break;  // 第二个位置颜色为 j
                                case 3: pri = k; break;  // 第三个位置颜色为 k
                                default: break;
                            }
                            
                            // 打印 pri 对应的颜色名
                            switch (pri) {

习题

1.定义一个结构体变量(包括年月日)。计算该日在本年中是第几天。

解题思路:

#include <stdio.h>

struct Date {
    int year;
    int month;
    int day;
};

// 判断是否是闰年
int isLeapYear(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

// days函数:计算该日在本年中是第几天
int days(struct Date date) {
    // 每个月的天数,默认非闰年
    int month_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (isLeapYear(date.year)) {
        month_days[1] = 29; // 闰年2月有29天
    }

    int total_days = 0;
    for (int i = 0; i < date.month - 1; i++) {
        total_days += month_days[i];
    }
    total_days += date.day;
    return total_days;
}

int main() {
    struct Date date;
    printf("请输入日期(年 月 日):");
    scanf("%d %d %d", &date.year, &date.month, &date.day);

    int day_of_year = days(date);
    printf("该日期是该年的第 %d 天\n", day_of_year);

    return 0;
}

2.写一个函数days,实现第一题的计算,由主函数将年月日传递给days函数,计算后将日子数传回主函数输出

解题思路:

#include <stdio.h>

struct Date {
    int year;
    int month;
    int day;
};

// 判断是否是闰年
int isLeapYear(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

// 计算该日在本年中是第几天
int days(struct Date date) {
    int month_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (isLeapYear(date.year)) {
        month_days[1] = 29;
    }

    int total_days = 0;
    for (int i = 0; i < date.month - 1; i++) {
        total_days += month_days[i];
    }
    total_days += date.day;
    return total_days;
}

int main() {
    struct Date date;
    printf("请输入日期(年 月 日):");
    scanf("%d %d %d", &date.year, &date.month, &date.day);

    printf("该日期是该年的第 %d 天\n", days(date));

    return 0;
}

3.编写一个print,打印一个学生的成绩数组,该数组有5个学生的数据记录,每个记录包括num,name,score[3],用主函数输入这些记录,用print函数输出这些记录。

解题思路:

#include <stdio.h>

struct Student {
    int num;
    char name[50];
    int score[3];
};

// print函数:输出学生记录
void print(struct Student students[], int n) {
    for (int i = 0; i < n; i++) {
        printf("学号: %d, 姓名: %s, 成绩: %d %d %d\n", 
            students[i].num, students[i].name, 
            students[i].score[0], students[i].score[1], students[i].score[2]);
    }
}

int main() {
    struct Student students[5];

    // 从主函数输入学生记录
    for (int i = 0; i < 5; i++) {
        printf("请输入学生%d的学号 姓名 成绩(3门课):\n", i + 1);
        scanf("%d %s %d %d %d", &students[i].num, students[i].name, 
              &students[i].score[0], &students[i].score[1], &students[i].score[2]);
    }

    // 调用print函数输出记录
    print(students, 5);

    return 0;
}

4.在第三题的基础上,编写一个input函数,用于输入5个学生的数据记录

解题思路:

#include <stdio.h>

struct Student {
    int num;
    char name[50];
    int score[3];
};

// input函数:输入学生记录
void input(struct Student students[], int n) {
    for (int i = 0; i < n; i++) {
        printf("请输入学生%d的学号 姓名 成绩(3门课):\n", i + 1);
        scanf("%d %s %d %d %d", &students[i].num, students[i].name, 
              &students[i].score[0], &students[i].score[1], &students[i].score[2]);
    }
}

// print函数:输出学生记录
void print(struct Student students[], int n) {
    for (int i = 0; i < n; i++) {
        printf("学号: %d, 姓名: %s, 成绩: %d %d %d\n", 
            students[i].num, students[i].name, 
            students[i].score[0], students[i].score[1], students[i].score[2]);
    }
}

int main() {
    struct Student students[5];

    // 调用input函数输入记录
    input(students, 5);

    // 调用print函数输出记录
    print(students, 5);

    return 0;
}

5.有10个学生,每个学生的数据包括学号、姓名、3门课程的成绩,从键盘输入10个学生数据,要求输出3门课程的总平均成绩,以及最高分的学生的数据(包括学号、姓名、三门课程成绩、平均成绩)

解题思路:

#include <stdio.h>

struct Student {
    int num;
    char name[50];
    int score[3];
    float average;
};

// 计算3门课程的总平均成绩
float calculateAverage(struct Student students[], int n) {
    int total[3] = {0, 0, 0};
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < 3; j++) {
            total[j] += students[i].score[j];
        }
    }
    return (total[0] + total[1] + total[2]) / (3.0 * n);
}

// 找到最高分的学生
struct Student findTopStudent(struct Student students[], int n) {
    struct Student top = students[0];
    for (int i = 1; i < n; i++) {
        if (students[i].average > top.average) {
            top = students[i];
        }
    }
    return top;
}

int main() {
    struct Student students[10];

    // 输入10个学生的数据记录
    for (int i = 0; i < 10; i++) {
        printf("请输入学生%d的学号 姓名 成绩(3门课):\n", i + 1);
        scanf("%d %s %d %d %d", &students[i].num, students[i].name, 
              &students[i].score[0], &students[i].score[1], &students[i].score[2]);
        students[i].average = (students[i].score[0] + students[i].score[1] + students[i].score[2]) / 3.0;
    }

    // 计算总平均成绩
    float total_average = calculateAverage(students, 10);
    printf("三门课程的总平均成绩为: %.2f\n", total_average);

    // 找到最高分的学生
    struct Student top_student = findTopStudent(students, 10);
    printf("最高分学生的学号: %d, 姓名: %s, 成绩: %d %d %d, 平均成绩: %.2f\n", 
           top_student.num, top_student.name, 
           top_student.score[0], top_student.score[1], top_student.score[2], top_student.average);

    return 0;
}

6.13个人围城一圈,从第一个人开始顺序报号1,2,3.凡是报到3的人退圈,找出最后留在圈子的人原来的序号,要求用链表实现

解题思路:

#include <stdio.h>
#include <stdlib.h>

// 定义链表节点结构
typedef struct Node {
    int num;                // 每个人的序号
    struct Node* next;      // 指向下一个节点
} Node;

// 创建一个新节点
Node* createNode(int num) {
    Node* newNode = (Node*)malloc(sizeof(Node)); // 分配内存给新节点
    newNode->num = num;       // 设置序号
    newNode->next = NULL;     // 初始化时,指针指向空
    return newNode;
}

// 构建环形链表
Node* createCircle(int n) {
    Node* head = createNode(1);  // 创建第一个人
    Node* prev = head;

    for (int i = 2; i <= n; i++) {   // 从第二个人开始创建节点
        Node* newNode = createNode(i);
        prev->next = newNode;    // 将前一个人连接到当前人
        prev = newNode;          // 当前人变为前一个人
    }

    prev->next = head;   // 最后一个人指向第一个人,形成环形链表
    return head;         // 返回环形链表的头节点
}

// 打印链表(调试用)
void printCircle(Node* head) {
    Node* temp = head;
    do {
        printf("%d -> ", temp->num);
        temp = temp->next;
    } while (temp != head);
    printf("(Back to %d)\n", head->num); // 最后指向第一个人
}

// 解决约瑟夫环问题,找出最后剩下的人的序号
int josephus(int n, int m) {
    Node* head = createCircle(n); // 创建n个人的环形链表
    Node* prev = NULL;
    Node* current = head;

    while (current->next != current) { // 当圈子里还有多个人时
        for (int i = 1; i < m; i++) {  // 报数到m-1的人
            prev = current;        // 记录当前人的前一个人
            current = current->next; // 移动到下一个人
        }

        // 当前报到m的人需要离开圈子
        printf("Person %d is out.\n", current->num);
        prev->next = current->next; // 前一个人的next指向当前人的下一个人
        free(current);              // 释放当前人的内存
        current = prev->next;       // 当前人移动到下一个人
    }

    int lastPerson = current->num;  // 最后剩下的人的序号
    free(current);                  // 释放最后一个人的内存
    return lastPerson;
}

int main() {
    int n = 13;  // 总人数
    int m = 3;   // 每次报到3的人出局

    // 调用函数找出最后剩下的人的序号
    int lastPerson = josephus(n, m);

    printf("The last person left is number %d\n", lastPerson);

    return 0;
}

7.在第九章例9.9和例9.10的基础上,写一个函数del,用来删除动态链表中指定的结点

解题思路:

#include <stdio.h>
#include <stdlib.h>

// 定义学生结构体
struct Student {
    long num;               // 学号
    float score;            // 成绩
    struct Student* next;   // 指向下一个学生的指针
};

// 创建链表的函数
struct Student* create(void) {
    struct Student* head = NULL;
    struct Student* p1, * p2;
    p1 = p2 = (struct Student*)malloc(sizeof(struct Student));
    printf("Enter student num and score (e.g. 1001 95.0), enter 0 to stop:\n");
    scanf("%ld %f", &p1->num, &p1->score);

    // 使用0作为结束输入的标志
    while (p1->num != 0) {
        n++;  // 记录链表的学生数量
        if (n == 1) {
            head = p1;  // 第一个学生成为头节点
        } else {
            p2->next = p1;  // 上一个节点的next指向当前节点
        }
        p2 = p1;  // p2移动到当前节点
        p1 = (struct Student*)malloc(sizeof(struct Student));
        scanf("%ld %f", &p1->num, &p1->score);
    }
    p2->next = NULL;  // 最后一个节点的next指向NULL
    return head;  // 返回头节点
}

// 打印链表的函数
void print(struct Student* head) {
    struct Student* p = head;
    printf("\nCurrent student records:\n");
    while (p != NULL) {
        printf("Student num: %ld, score: %.1f\n", p->num, p->score);
        p = p->next;
    }
}

// 删除指定学号的学生
struct Student* del(struct Student* head, long num) {
    struct Student *p = head, *prev = NULL;

    // 如果要删除的节点是头节点
    if (p != NULL && p->num == num) {
        head = p->next;  // 头节点更新为下一个节点
        free(p);  // 释放旧的头节点
        printf("Deleted student with num: %ld\n", num);
        return head;
    }

    // 查找要删除的节点
    while (p != NULL && p->num != num) {
        prev = p;  // 保存前一个节点
        p = p->next;  // 移动到下一个节点
    }

    // 找到节点
    if (p == NULL) {
        printf("Student with num %ld not found.\n", num);
        return head;  // 未找到,返回原链表
    }

    // 删除节点
    prev->next = p->next;  // 前一个节点的next指向当前节点的下一个节点
    free(p);  // 释放被删除节点的内存
    printf("Deleted student with num: %ld\n", num);
    return head;
}

// 主函数
int main() {
    struct Student* head;
    head = create();  // 创建链表
    print(head);  // 打印链表

    // 删除指定的学生
    long num;
    printf("Enter the student num to delete: ");
    scanf("%ld", &num);
    head = del(head, num);  // 删除指定学号的学生

    // 打印删除后的链表
    print(head);

    return 0;
}

8.写一个函数insert,用来向一个动态链表插入结点

解题思路:

#include <stdio.h>
#include <stdlib.h>

// 定义学生结构体
struct Student {
    long num;               // 学号
    float score;            // 成绩
    struct Student* next;   // 指向下一个学生的指针
};

// 创建链表的函数
struct Student* create(void) {
    struct Student* head = NULL;
    struct Student* p1, * p2;
    p1 = p2 = (struct Student*)malloc(sizeof(struct Student));
    printf("Enter student num and score (e.g. 1001 95.0), enter 0 to stop:\n");
    scanf("%ld %f", &p1->num, &p1->score);

    while (p1->num != 0) {
        if (head == NULL) {
            head = p1;  // 第一个学生成为头节点
        } else {
            p2->next = p1;  // 上一个节点的next指向当前节点
        }
        p2 = p1;  // p2移动到当前节点
        p1 = (struct Student*)malloc(sizeof(struct Student));
        scanf("%ld %f", &p1->num, &p1->score);
    }
    p2->next = NULL;  // 最后一个节点的next指向NULL
    return head;  // 返回头节点
}

// 打印链表的函数
void print(struct Student* head) {
    struct Student* p = head;
    printf("\nCurrent student records:\n");
    while (p != NULL) {
        printf("Student num: %ld, score: %.1f\n", p->num, p->score);
        p = p->next;
    }
}

// 插入新节点的函数
struct Student* insert(struct Student* head, long num, float score) {
    struct Student* newNode = (struct Student*)malloc(sizeof(struct Student));
    struct Student* p = head;
    struct Student* prev = NULL;

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

    // 如果链表为空,直接插入为头节点
    if (head == NULL) {
        return newNode;
    }

    // 如果新节点应插入到头部
    if (num < head->num) {
        newNode->next = head;
        return newNode;
    }

    // 查找合适的位置插入(按学号升序)
    while (p != NULL && p->num < num) {
        prev = p;  // 记录前一个节点
        p = p->next;
    }

    // 插入新节点
    prev->next = newNode;  // 前一个节点的next指向新节点
    newNode->next = p;     // 新节点的next指向后面的节点

    return head;
}

// 主函数
int main() {
    struct Student* head;
    head = create();  // 创建链表
    print(head);  // 打印链表

    // 插入新节点
    long num;
    float score;
    printf("\nEnter the student num and score to insert: ");
    scanf("%ld %f", &num, &score);
    head = insert(head, num, score);  // 向链表中插入新学生

    // 打印插入后的链表
    print(head);

    return 0;
}

9.结合例9.9(建立链表的函数create)例9.10(输出结点的函数print)和本章习题第七题(删除链表中结点的函数del)、第八题(插入结点的函数insert),再编写一个主函数,先后调用这些函数。用一上午个函数组成一个程序,实现链表的建立、输出、删除和插入,在主函数中指定需要删除和插入的结点数据。

解题思路:

#include <stdio.h>
#include <stdlib.h>

// 定义学生结构体
struct Student {
    long num;               // 学号
    float score;            // 成绩
    struct Student* next;   // 指向下一个学生的指针
};

// 创建链表的函数
struct Student* create(void) {
    struct Student* head = NULL;
    struct Student* p1, * p2;
    p1 = p2 = (struct Student*)malloc(sizeof(struct Student));
    printf("Enter student num and score (e.g. 1001 95.0), enter 0 to stop:\n");
    scanf("%ld %f", &p1->num, &p1->score);

    while (p1->num != 0) {
        if (head == NULL) {
            head = p1;  // 第一个学生成为头节点
        } else {
            p2->next = p1;  // 上一个节点的next指向当前节点
        }
        p2 = p1;  // p2移动到当前节点
        p1 = (struct Student*)malloc(sizeof(struct Student));
        scanf("%ld %f", &p1->num, &p1->score);
    }
    p2->next = NULL;  // 最后一个节点的next指向NULL
    return head;  // 返回头节点
}

// 打印链表的函数
void print(struct Student* head) {
    struct Student* p = head;
    printf("\nCurrent student records:\n");
    while (p != NULL) {
        printf("Student num: %ld, score: %.1f\n", p->num, p->score);
        p = p->next;
    }
}

// 删除指定学号的学生
struct Student* del(struct Student* head, long num) {
    struct Student *p = head, *prev = NULL;

    // 如果要删除的节点是头节点
    if (p != NULL && p->num == num) {
        head = p->next;  // 头节点更新为下一个节点
        free(p);  // 释放旧的头节点
        printf("Deleted student with num: %ld\n", num);
        return head;
    }

    // 查找要删除的节点
    while (p != NULL && p->num != num) {
        prev = p;  // 记录前一个节点
        p = p->next;  // 移动到下一个节点
    }

    // 找到节点
    if (p == NULL) {
        printf("Student with num %ld not found.\n", num);
        return head;  // 未找到,返回原链表
    }

    // 删除节点
    prev->next = p->next;  // 前一个节点的next指向当前节点的下一个节点
    free(p);  // 释放被删除节点的内存
    printf("Deleted student with num: %ld\n", num);
    return head;
}

// 插入新节点的函数
struct Student* insert(struct Student* head, long num, float score) {
    struct Student* newNode = (struct Student*)malloc(sizeof(struct Student));
    struct Student* p = head;
    struct Student* prev = NULL;

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

    // 如果链表为空,直接插入为头节点
    if (head == NULL) {
        return newNode;
    }

    // 如果新节点应插入到头部
    if (num < head->num) {
        newNode->next = head;
        return newNode;
    }

    // 查找合适的位置插入(按学号升序)
    while (p != NULL && p->num < num) {
        prev = p;  // 记录前一个节点
        p = p->next;
    }

    // 插入新节点
    prev->next = newNode;  // 前一个节点的next指向新节点
    newNode->next = p;     // 新节点的next指向后面的节点

    return head;
}

// 主函数
int main() {
    struct Student* head;

    // 创建链表
    head = create();  // 使用create函数创建链表
    print(head);  // 打印链表

    // 删除指定的学生
    long num_to_delete;
    printf("\nEnter the student num to delete: ");
    scanf("%ld", &num_to_delete);
    head = del(head, num_to_delete);  // 删除指定学号的学生
    print(head);  // 打印删除后的链表

    // 插入新学生
    long num_to_insert;
    float score_to_insert;
    printf("\nEnter the student num and score to insert: ");
    scanf("%ld %f", &num_to_insert, &score_to_insert);
    head = insert(head, num_to_insert, score_to_insert);  // 向链表中插入新学生
    print(head);  // 打印插入后的链表

    return 0;
}

10.已有a、b两个链表,每个链表中的结点包括学号、成绩。要求把两个链表合并,按学号升序排序。

解题思路:

#include <stdio.h>
#include <stdlib.h>

// 定义学生结构体
struct Student {
    long num;               // 学号
    float score;            // 成绩
    struct Student* next;   // 指向下一个学生的指针
};

// 创建链表的函数
struct Student* create(void) {
    struct Student* head = NULL;
    struct Student* p1, * p2;
    p1 = p2 = (struct Student*)malloc(sizeof(struct Student));
    printf("Enter student num and score (e.g. 1001 95.0), enter 0 to stop:\n");
    scanf("%ld %f", &p1->num, &p1->score);

    while (p1->num != 0) {
        if (head == NULL) {
            head = p1;  // 第一个学生成为头节点
        } else {
            p2->next = p1;  // 上一个节点的next指向当前节点
        }
        p2 = p1;  // p2移动到当前节点
        p1 = (struct Student*)malloc(sizeof(struct Student));
        scanf("%ld %f", &p1->num, &p1->score);
    }
    p2->next = NULL;  // 最后一个节点的next指向NULL
    return head;  // 返回头节点
}

// 打印链表的函数
void print(struct Student* head) {
    struct Student* p = head;
    printf("\nCurrent student records:\n");
    while (p != NULL) {
        printf("Student num: %ld, score: %.1f\n", p->num, p->score);
        p = p->next;
    }
}

// 合并两个链表的函数
struct Student* merge(struct Student* a, struct Student* b) {
    struct Student dummy;  // 哨兵节点
    struct Student* tail = &dummy;  // 用于构建新链表
    dummy.next = NULL;

    // 合并两个链表
    while (a != NULL && b != NULL) {
        if (a->num <= b->num) {
            tail->next = a;
            a = a->next;
        } else {
            tail->next = b;
            b = b->next;
        }
        tail = tail->next;
    }

    // 处理剩余的节点
    if (a != NULL) {
        tail->next = a;
    } else {
        tail->next = b;
    }

    return dummy.next;
}

// 主函数
int main() {
    struct Student* a;
    struct Student* b;
    struct Student* merged;

    printf("Create first list:\n");
    a = create();  // 创建第一个链表
    print(a);  // 打印第一个链表

    printf("Create second list:\n");
    b = create();  // 创建第二个链表
    print(b);  // 打印第二个链表

    // 合并链表并排序
    merged = merge(a, b);
    printf("\nMerged and sorted list:\n");
    print(merged);  // 打印合并后的链表

    return 0;
}

11.有两个链表a和b,设结点中包含学号、姓名。从a链表中删去与b链表中有相同学号的那些结点。

解题思路:

#include <stdio.h>
#include <stdlib.h>

// 定义学生结构体
struct Student {
    long num;               // 学号
    char name[50];          // 姓名
    struct Student* next;   // 指向下一个学生的指针
};

// 创建链表的函数
struct Student* create(void) {
    struct Student* head = NULL;
    struct Student* p1, * p2;
    p1 = p2 = (struct Student*)malloc(sizeof(struct Student));
    printf("Enter student num and name (e.g. 1001 John), enter 0 to stop:\n");
    scanf("%ld %49s", &p1->num, p1->name);

    while (p1->num != 0) {
        if (head == NULL) {
            head = p1;  // 第一个学生成为头节点
        } else {
            p2->next = p1;  // 上一个节点的next指向当前节点
        }
        p2 = p1;  // p2移动到当前节点
        p1 = (struct Student*)malloc(sizeof(struct Student));
        scanf("%ld %49s", &p1->num, p1->name);
    }
    p2->next = NULL;  // 最后一个节点的next指向NULL
    return head;  // 返回头节点
}

// 打印链表的函数
void print(struct Student* head) {
    struct Student* p = head;
    printf("\nCurrent student records:\n");
    while (p != NULL) {
        printf("Student num: %ld, name: %s\n", p->num, p->name);
        p = p->next;
    }
}

// 从链表a中删除与链表b中有相同学号的节点
struct Student* deleteMatchingNodes(struct Student* a, struct Student* b) {
    struct Student *p, *prev, *temp;
    struct Student* head = a;
    
    // 遍历链表b,将学号存储在哈希表中
    struct Student* hash[1000] = {NULL}; // 简单的哈希表,假设学号范围在[0, 999]内
    while (b != NULL) {
        hash[b->num] = b;  // 哈希表的索引是学号
        b = b->next;
    }
    
    p = head;
    prev = NULL;
    
    while (p != NULL) {
        if (hash[p->num] != NULL) {
            // 学号匹配,删除节点
            if (prev == NULL) {
                head = p->next;  // 删除头节点
            } else {
                prev->next = p->next;  // 删除中间或尾部节点
            }
            temp = p;
            p = p->next;
            free(temp);  // 释放被删除节点的内存
        } else {
            // 学号不匹配,继续遍历
            prev = p;
            p = p->next;
        }
    }
    return head;
}

// 主函数
int main() {
    struct Student* a;
    struct Student* b;
    
    // 创建链表a和b
    printf("Create list A:\n");
    a = create();  // 创建链表a
    print(a);  // 打印链表a

    printf("Create list B:\n");
    b = create();  // 创建链表b
    print(b);  // 打印链表b

    // 从链表a中删除与链表b中有相同学号的节点
    a = deleteMatchingNodes(a, b);
    printf("\nList A after deletion:\n");
    print(a);  // 打印删除后的链表a

    return 0;
}

12.建立一个链表,每个结点包括:学号、姓名、性别、年龄。输入一个年龄,如果链表中的结点所包含的年龄,则将此结点删去。

解题思路:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 定义学生结构体
struct Student {
    long num;               // 学号
    char name[50];          // 姓名
    char gender;            // 性别
    int age;                // 年龄
    struct Student* next;   // 指向下一个学生的指针
};

// 创建链表的函数
struct Student* create(void) {
    struct Student* head = NULL;
    struct Student* p1, * p2;
    p1 = p2 = (struct Student*)malloc(sizeof(struct Student));
    
    printf("Enter student num, name, gender, age (e.g. 1001 John M 20), enter 0 to stop:\n");
    scanf("%ld %49s %c %d", &p1->num, p1->name, &p1->gender, &p1->age);

    while (p1->num != 0) {
        if (head == NULL) {
            head = p1;  // 第一个学生成为头节点
        } else {
            p2->next = p1;  // 上一个节点的next指向当前节点
        }
        p2 = p1;  // p2移动到当前节点
        p1 = (struct Student*)malloc(sizeof(struct Student));
        scanf("%ld %49s %c %d", &p1->num, p1->name, &p1->gender, &p1->age);
    }
    p2->next = NULL;  // 最后一个节点的next指向NULL
    return head;  // 返回头节点
}

// 打印链表的函数
void print(struct Student* head) {
    struct Student* p = head;
    printf("\nCurrent student records:\n");
    while (p != NULL) {
        printf("Student num: %ld, name: %s, gender: %c, age: %d\n", p->num, p->name, p->gender, p->age);
        p = p->next;
    }
}

// 从链表中删除指定年龄的节点
struct Student* deleteByAge(struct Student* head, int age) {
    struct Student *p = head, *prev = NULL, *temp;

    while (p != NULL) {
        if (p->age == age) {
            // 学龄匹配,删除节点
            if (prev == NULL) {
                head = p->next;  // 删除头节点
            } else {
                prev->next = p->next;  // 删除中间或尾部节点
            }
            temp = p;
            p = p->next;
            free(temp);  // 释放被删除节点的内存
        } else {
            // 学龄不匹配,继续遍历
            prev = p;
            p = p->next;
        }
    }
    return head;
}

// 主函数
int main() {
    struct Student* head;

    // 创建链表
    head = create();  // 使用create函数创建链表
    print(head);  // 打印链表

    // 输入要删除的年龄
    int age_to_delete;
    printf("\nEnter the age to delete: ");
    scanf("%d", &age_to_delete);

    // 从链表中删除指定年龄的节点
    head = deleteByAge(head, age_to_delete);
    printf("\nList after deletion:\n");
    print(head);  // 打印删除后的链表

    return 0;
}

  • 22
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值