第九章 结构体
文章目录
- 第九章 结构体
- 例9.1 把一个学生的信息,包括学号、姓名、性别、地址放在一个结构体变量中,然后输出这个学生的信息
- 例9.2 输入两个学生的学号姓名和成绩,输出成绩较高的学生的学号、姓名和成绩
- 例9.3 有三个候选人,每个选民只能投票选一人,要求编一个统计选票的程序,先后输入备选人的名字,最后输出个人得票结果
- 例9.4 有n个学生的信息(学号、姓名、成绩),要求按照成绩的高低顺序输出各学生的信息。
- 例9.5 通过指向结构体变量的指针输出结构体变量中成员信息
- 例9.6 有3个学生的信息,放在结构体数组中,要求输出全部学生的信息。
- 例9.7 有n个结构体变量,内含学生学号、姓名和3门课程的成绩。要求输出平均成绩最高的学生的信息(包括学号、姓名、3门课程成绩和平均成绩)
- 例9.8建立一个如图9.9的简单链表,它由3个学生数据的结点组成,要求输出各节点中数据。
- 例9.9 写一函数建立由3名学生数据的单项动态链表
- 例9.10 编写一个输出链表的函数print
- 例9.11 有若干各人员的数据,其中有学生和教师。学生的数据中包括:姓名、好吗、性别、职业、班级。教师:姓名、号码、性别、职业、职务,要求用同一个表格处理
- 例9.12 口袋里有红黄蓝白黑五种颜色的球若干个,每次从口袋中先后取出3个球,问得到3个不同颜色的球的可能取法,输出每种排列的情况
- 习题
- 1.定义一个结构体变量(包括年月日)。计算该日在本年中是第几天。
- 2.写一个函数days,实现第一题的计算,由主函数将年月日传递给days函数,计算后将日子数传回主函数输出
- 3.编写一个print,打印一个学生的成绩数组,该数组有5个学生的数据记录,每个记录包括num,name,score[3],用主函数输入这些记录,用print函数输出这些记录。
- 4.在第三题的基础上,编写一个input函数,用于输入5个学生的数据记录
- 5.有10个学生,每个学生的数据包括学号、姓名、3门课程的成绩,从键盘输入10个学生数据,要求输出3门课程的总平均成绩,以及最高分的学生的数据(包括学号、姓名、三门课程成绩、平均成绩)
- 6.13个人围城一圈,从第一个人开始顺序报号1,2,3.凡是报到3的人退圈,找出最后留在圈子的人原来的序号,要求用链表实现
- 7.在第九章例9.9和例9.10的基础上,写一个函数del,用来删除动态链表中指定的结点
- 8.写一个函数insert,用来向一个动态链表插入结点
- 9.结合例9.9(建立链表的函数create)例9.10(输出结点的函数print)和本章习题第七题(删除链表中结点的函数del)、第八题(插入结点的函数insert),再编写一个主函数,先后调用这些函数。用一上午个函数组成一个程序,实现链表的建立、输出、删除和插入,在主函数中指定需要删除和插入的结点数据。
- 10.已有a、b两个链表,每个链表中的结点包括学号、成绩。要求把两个链表合并,按学号升序排序。
- 11.有两个链表a和b,设结点中包含学号、姓名。从a链表中删去与b链表中有相同学号的那些结点。
- 12.建立一个链表,每个结点包括:学号、姓名、性别、年龄。输入一个年龄,如果链表中的结点所包含的年龄,则将此结点删去。
例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;
}