c语言程序设计(第二版)余贞侠课后习题解析-第九章(自定义数据类型)

本文展示了四个用C语言实现的示例,涉及日期计算、学生成绩管理系统、链表操作和链表操作的多种功能。包括统计不及格学生、成绩排序、链表数据输入输出、链表节点查找替换、链表交集和并集计算以及报数游戏。这些示例涵盖了数据结构和算法的基础应用。
摘要由CSDN通过智能技术生成
   自己写的,也参考了网上部分优秀的博主,只是给自己做一个简单的记录

1.定义一个个结构体变量,包括年、月、日数据。计算该日在本年中是第几天,注意闰年问题。

#define  _CRT_SECURE_NO_WARNINGS /*防止scanf使用报错*/
#include<stdio.h>

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

int main()
{
	struct Date data;
	
	printf("请输入年/月/日:");
	scanf("%d/%d/%d", &data.year, &data.month, &data.day);
	int mon[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
	int sum = data.day, i;
	//如果输入的年份为闰年,则需要将第二月的天数改为29天
	if (data.year % 4 == 0 && data.year % 100 != 0 || data.year % 400 == 0)
	{
		mon[2] = 29;
	}
	for (i = 0; i < data.month; i++)
	{
		sum += mon[i];
	}
	printf("\n%d/%d/%d是%d年的第%d天.\n",data.year,data.month,data.day,data.year,sum);
	printf("\n");
	return 0;
}

在这里插入图片描运行述

2.做一个针对10个学生的简易成绩管理系统。学生信息包括学号、姓名、年龄、三门课成绩。功能包括统计不及格的名单并显示,对平时成绩进行从高到低排序。

#define  _CRT_SECURE_NO_WARNINGS /*防止scanf使用报错*/
#include<stdio.h>
#include <stdlib.h>
#define N 3				//课程数
#define M 5 	    //学生人数

struct Student
{
	char num[12];		//学号
	char name[20];		//姓名
	int age;			//年龄
	float score[N];		//课程成绩
};

//struct Student Stu[N];

//功能界面函数
void printMenu()
{
	printf("\n欢迎来到简易学生管理系统,请输入序号按enter以选择功能:\n");
	printf("1 录入学生数据\n");
	printf("2 统计不及格的名单\n");
	printf("3 平时成绩排序\n");
	printf("0 退出\n");
	printf("============================================================\n");
}

//信息输入函数
void info_input(struct Student* s, int m)
{
	int i, j;
	printf("请输入%d名学生的信息....\n",m);
	for (i = 0; i < m; i++)
	{
		printf("请输入学生_%d的学号:", i + 1);
		scanf("%s", s[i].num);
		printf("请输入学生_%d的姓名:", i + 1);
		scanf("%s", s[i].name);
		printf("请输入学生_%d的年龄:", i + 1);
		scanf("%d", &s[i].age);
		printf("请输入学生_%d的%d门课程成绩:\n", i + 1, N);
		for (j = 0; j < N; j++)
		{
			printf("第%d门课分数:", j + 1);
			scanf("%f", &s[i].score[j]);
		}
		printf("\n");
	}
}

//统计不及格的学生名单并输出
void fail_test_stu(struct Student* s, int m, int n)/*学生人数,课程数量*/
{
	struct Student fail_stu[M];
	int i, j, k = 0;
	for (i = 0; i < m; i++)
	{
		for (j = 0; j < n; j++)
		{
			if (s[i].score[j] < 90.0)
			{
				fail_stu[k++] = s[i];
				break;
			}
		}
	}

	printf("不及格学生名单如下:\n");
	//输出详细信息
	while (k-- > 0)
	{
		printf("学号:%s\n姓名:%s\n年龄:%d\n",
			fail_stu[k].num, fail_stu[k].name, fail_stu[k].age);
		printf("语文:%.2f\t数学:%.2f\t英语:%.2f\t\n",
			fail_stu[k].score[0], fail_stu[k].score[1], fail_stu[k].score[2]);
	}
}

//定义排序函数
void swap(struct Student* s, int i, int j)
{
	struct Student temp;
	temp = s[i];
	s[i] = s[j];
	s[j] = temp;
}

//对平时成绩进行从高到低的排序
void score_sort_stu(struct Student* s, int m, int n)
{
	int i, j, k;
	for (i = 0; i < m; i++)
	{
		for (j = i + 1; j < m; j++)
		{
			for (k = 0; k < n; k++)
			{
				if (s[i].score[k] < s[j].score[k])
					swap(s, i, j);
			}
		}
	}

	printf("排序后的成绩从高到低的顺序如下:\n");
	for (i = 0; i < m; i++)
	{
		printf("NO. %d\n", i + 1);
		printf("学号:%s\n姓名:%s\n年龄:%d\n",
			s[i].num, s[i].name, s[i].age);
		printf("语文:%.2f\t数学:%.2f\t英语:%.2f\t\n",
			s[i].score[0], s[i].score[1], s[i].score[2]);
		printf("\n");
	}
	printf("\n");
	
}

int main()
{
	struct Student data[M];
	while (1)
	{
		printMenu();
		int choice;
		scanf("%d", &choice);
		if (!choice)
		{
			printf("\n感谢使用,欢迎下次使用,再见!\n");
			exit(0);
		}
		else
		{
			if (1 == choice)
			{
				info_input(data, M);
				printf("------------------\n");
			}
			else if (2 == choice)
			{
				fail_test_stu(data, M, N);
				printf("------------------\n");
			}
			else if (3 == choice)
			{
				score_sort_stu(data, M, N);
				printf("------------------\n");
			}
			else
			{
				printf("没有该选项\n");	
			}
		}
	}
	return 0;
}

在这里插入图片描述

3.有10个学生的信息,包括学号、姓名、年龄,组成结构体数组。将该数组的10个学生数据读出形成链表。

#define  _CRT_SECURE_NO_WARNINGS /*防止scanf使用报错*/
#include<stdio.h>
#define M 4

struct Student
{
	char num[12];
	char name[20];
	int age;
	struct Student* next;		//建立结构体类型的next指针
}Stu[M];

//输入数据
void info_input()
{
	int i;
	for (i = 0; i < M; i++)
	{
		printf("请输入学生_%d的学号:",i+1);
		scanf("%s", Stu[i].num);
		printf("请输入学生_%d的姓名:",i+1);
		scanf("%s", Stu[i].name);
		printf("请输入学生_%d的年龄:",i+1);
		scanf("%d", &Stu[i].age);
		printf("\n");
	}
}

//通过链表方式读出学生信息
void info_ouput(struct Student* s, int n)
{
	int i;
	struct Student* head = &s[0];		//将结构体数组的首地址赋值给头指针
	for (i = 1; i < n; i++)
	{
		s[i - 1].next = &s[i];
	}

	struct Student* p = head;		//建立p指针来移动输出数据
	printf("学生信息输出如下:\n");
	while (p != NULL)
	{
		printf("学号:%s\t姓名:%s\t年龄:%d\t\n",p->num,p->name,p->age);
		p = p->next;
	}
}

int main()
{
	info_input();
	info_ouput(Stu, M);
	printf("\n");
	return 0;
}

在这里插入图片描述

4.给定一个链表,每个链表中的结点包括学号、成绩。在其中查找某个学号的学生结点,将其成绩替换成指定的新成绩。

#define  _CRT_SECURE_NO_WARNINGS /*防止scanf使用报错*/
#include<stdio.h>
#include<stdlib.h>

struct Student
{
	int num;			//学号
	float score;		//成绩
	struct Student* next;
};

struct List
{
	struct Student* head;
	struct Student* tail;
};

//创建链表
struct List* creat()
{
	//创建节点并初始化节点
	struct Student* p = (struct Student*)malloc(sizeof(struct Student));
	p->next = NULL;			

	//创建链表
	struct List* list = (struct List*)malloc(sizeof(struct List));

	//执行置空操作
	list->head = p;
	list->tail = p;
	return list;
}


//插入数据
void insert(struct List* list, int num, float score)
{
	//创建学生结构体类型的结点
	struct Student* node = (struct Student*)malloc(sizeof(struct Student));
	
	node->num = num;
	node->score = score;
	node->next = NULL;
	
	//链表尾指针后移,表尾插入数据
	list->tail->next = node;
	list->tail = list->tail->next;		
}

//输出链表
void printlist(struct List* list)
{
	//头结点无数据,需要从它的下一个节点开始进行操作
	struct Student* p = list->head->next;
	
	while (p != NULL)
	{
		printf("学号:%d\t分数:%6.2f\t\n", p->num, p->score);
		p = p->next;
	}
}

//查找学号
struct Student* findNumb(struct List* list, int numb)
{
	struct Student* p = list->head->next;
	
	while (p != NULL)
	{
		if (p->num == numb)
		{
			return p;
		}
	 	p = p->next;			//没找到的话,指针继续后移
	}
	return NULL;
}


//替换对应学号的成绩
void scoreReplace(struct List* list, int numb, float Score)
{
	//这里需要先找到输入的学生信息的对应结点
	struct Student* node = findNumb(list, numb);
	
	if (node != NULL)
	{
		node->score = Score;
	}
}

int main()
{
	struct List* stu_info_list = creat();
	
	insert(stu_info_list, 202106, 98);
	insert(stu_info_list, 202112, 90);
	insert(stu_info_list, 202116, 88);
	insert(stu_info_list, 202119, 96);
	insert(stu_info_list, 202123, 78);
	
	//将插入数据生成的链表内容输出
	printf("链表原数据如下:\n");
	printlist(stu_info_list);
	
	//查找与替换
	scoreReplace(stu_info_list, 202123, 100);
	printf("\n链表替换后的数据如下:\n");
	printlist(stu_info_list);
	printf("\n");
	
	return 0;
}

在这里插入图片描述

5.给定两个链表,每个链表中的结点包括学号、成绩。求两个链表的交集。

#define  _CRT_SECURE_NO_WARNINGS /*防止scanf使用报错*/
#include<stdio.h>
#include<stdlib.h>

struct Student
{
	int number;
	float score;
	struct Student* next;
};

struct List
{
	//建立带头、尾指针的链表
	struct Student* head;		
	struct Student* tail;
};

//建立链表
struct List* creatList()
{
	struct Student* p = (struct Student*)malloc(sizeof(struct Student));
	p->next = NULL;
	
	//创建链表并初始化
	struct List* list = (struct List*)malloc(sizeof(struct List));
	list->head = p;
	list->tail = p;

	return list;
}

//插入数据
void insertData(struct List* list, int num, float score)
{
	struct Student* node = (struct Student*)malloc(sizeof(struct Student));

	node->number = num;
	node->score = score;
	node->next = NULL;

	//表尾插入数据,尾指针后移
	list->tail->next = node;
	list->tail = list->tail->next;
}


//打印链表
void printList(struct List* list)
{
	struct Student* p = list->head->next;
	
	while (p != NULL)
	{
		printf("学号:%d\t分数:%.2f\t\n", p->number, p->score);
		p = p->next;
	}
}

//求两个链表的交集
struct List* commonPartList(struct List* listOne, struct List* listTwo)
{
	struct List* comList = creatList();
	struct Student* p1 = listOne->head->next;

	while (p1 != NULL)
	{
		struct Student* p2 = listTwo->head->next;

		while (p2 != NULL)
		{
			//比较学号与分数是否相等
			if (p1->number == p2->number && p1->score == p2->score)
			{
				insertData(comList, p1->number, p1->score);
				break;
			}
			p2 = p2->next;			//指针后移
		}
		p1 = p1->next;				//指针后移
	}
	return comList;
}

int main()
{
	//建立链表1
	printf("链表1的数据如下:\n");
	struct List* list_1 = creatList();
	insertData(list_1, 201806, 90);
	insertData(list_1, 201808, 80);
	insertData(list_1, 201812, 88);
	insertData(list_1, 201818, 100);
	printList(list_1);
	printf("\n");


	//建立链表2
	printf("链表2的数据如下:\n");
	struct List* list_2 = creatList();
	insertData(list_2, 201806, 90);
	insertData(list_2, 201808, 80);
	insertData(list_2, 201813, 96);
	insertData(list_2, 201818, 100);
	printList(list_2);
	printf("\n");

	//上面两个链表的交集
	struct List* commonList = commonPartList(list_1, list_2);
	printf("两个链表的交集部分如下:\n");
	printList(commonList);
	printf("\n");
	return 0;
}

在这里插入图片描述

6.给定两个链表a与b,每个链表中的结点包括学号、成绩。要求从a链表中删除与b表有相同学号的结点。

#define  _CRT_SECURE_NO_WARNINGS /*防止scanf使用报错*/
#include<stdio.h>
#include<stdlib.h>

struct Student
{
	int number;
	float score;
	struct Student* next;
};

struct List
{
	struct Student* head;
	struct Student* tail;
};

//创建链表
struct List* creatDataList()
{
	struct Student* p = (struct Student*)malloc(sizeof(struct Student));
	p->next = NULL;

	struct List* list = (struct List*)malloc(sizeof(struct List));
	list->head = p;
	list->tail = p;
	return list;
}


//插入数据
void insertData(struct List* list, int number, float score)
{
	struct Student* node = (struct Student*)malloc(sizeof(struct Student));

	node->number = number;
	node->score = score;
	node->next = NULL;

	list->tail->next = node;				//在链尾插入数据
	list->tail = list->tail->next;			//链表指针后移
}


//打印链表数据
void printListData(struct List* list)
{
	struct Student* p = list->head->next;	//从头指针开始后移
	while (p != NULL)
	{
		printf("学号:%d\t分数:%.2f\t\n", p->number, p->score);
		p = p->next;
	}
}

//删除两个链表有相同学号的结点
void delCommonNode(struct List* list, int num)
{
	struct Student* newNode = list->head;		//建立一个学生结构体的结点
	struct Student* p = newNode->next;			//从这个结点的下一个结点开始移动

	while (p != NULL)
	{
		if (p->number == num)
		{
			//删除这个相同学号的结点并释放
			newNode->next = p->next;
			p->next = NULL;

			free(p);
			break;
		}
		newNode = newNode->next;
		p = p->next;
	}
}

//删除链表A中与链表B相同学号的结点
void delSameNum(struct List* A, struct List* B)
{
	struct Student* p1 = A->head->next;

	while (p1 != NULL)
	{
		struct Student* p2 = B->head->next;
		struct Student* temp = p1->next;

		while (p2 != NULL)
		{
			if (p1->number == p2->number)
			{
				delCommonNode(A, p1->number);
				break;
			}
			p2 = p2->next;
		}
		p1 = temp;
	}
}


int main()
{
	printf("链表A的数据如下:\n");
	struct List* listA = creatDataList();
	insertData(listA, 201806, 90);
	insertData(listA, 201808, 80);
	insertData(listA, 201812, 88);
	insertData(listA, 201818, 100);
	printListData(listA);
	printf("\n");

	printf("链表B的数据如下:\n");
	struct List* listB = creatDataList();
	insertData(listB, 201806, 90);
	insertData(listB, 201808, 80);
	insertData(listB, 201813, 96);
	insertData(listB, 201818, 100);
	printListData(listB);
	printf("\n");


	printf("删除相同学号的结点后,链表A的余留数据如下:\n");
	delSameNum(listA, listB);
	printListData(listA);
	printf("\n");
	return 0;
}

在这里插入图片描述

7.给定两个链表,每个链表中的结点包括学号、成绩,并均为学号升序排列。求两链表的并集,并集的结果仍按学号升序排列。

#define  _CRT_SECURE_NO_WARNINGS /*防止scanf使用报错*/
#include<stdio.h>
#include<stdlib.h>

struct Student
{
	int number;
	float score;
	struct Student* next;
};

struct List
{
	struct Student* head;
	struct Student* tail;
};

//创建链表
struct List* creatDataList()
{
	struct Student* p = (struct Student*)malloc(sizeof(struct Student));
	p->next = NULL;

	struct List* list = (struct List*)malloc(sizeof(struct List));
	list->head = p;
	list->tail = p;
	
	return list;
}


//插入数据
void insertData(struct List* list, int num, float score)
{
	struct Student* node = (struct Student*)malloc(sizeof(struct Student));
	node->number = num;
	node->score = score;
	node->next = NULL;

	list->tail->next = node;
	list->tail = list->tail->next;
}

//打印链表
void printDataList(struct List* list)
{
	struct Student* p = list->head->next;

	while (p!=NULL)
	{
		printf("学号:%d\t分数:%.2f\n", p->number, p->score);
		p = p->next;
	}
}

//求两个链表的并集
struct List* allDataList(struct List* listA, struct List* listB)
{
	struct List* allList = creatDataList();

	struct Student* p1 = listA->head->next;
	struct Student* p2 = listB->head->next;

	//并集按照学号升序排列
	while (p1 !=NULL&& p2 != NULL)
	{
		if (p1->number < p2->number)
		{
			insertData(allList, p1->number, p1->score);
			p1 = p1->next;
		}
		else
		{
			insertData(allList, p2->number, p2->score);
			p2 = p2->next;
		}
	}

	while (p1!=NULL)
	{
		insertData(allList, p1->number, p1->score);
		p1 = p1->next;
	}
	while (p2!=NULL )
	{
		insertData(allList, p2->number, p2->score);
		p2 = p2->next;
	}
	return allList;
}

int main()
{
	printf("链表A的数据如下:\n");
	struct List* listA = creatDataList();
	insertData(listA, 201803, 90);
	insertData(listA, 201807, 80);
	insertData(listA, 201812, 88);
	insertData(listA, 201819, 100);
	printDataList(listA);
	printf("\n");

	printf("链表B的数据如下:\n");
	struct List* listB = creatDataList();
	insertData(listB, 201806, 90);
	insertData(listB, 201808, 80);
	insertData(listB, 201813, 96);
	insertData(listB, 201818, 100);
	printDataList(listB);
	printf("\n");

	printf("链表A、B的并集数据如下:\n");
	struct List* unionList = allDataList(listA, listB);
	printDataList(unionList);
	printf("\n");

	return 0;
}

在这里插入图片描述

8.10人围成一圈,并从1到10依次分配编号。从编号为1的人开始依次报数1,2,3,报3的人退出,余下的人继续从1开始依次报数,到3退圈。当最后一人留在圈时求其原来的编号。

#define  _CRT_SECURE_NO_WARNINGS /*防止scanf使用报错*/
#include<stdio.h>
#define M 3
#define MAX 100

int main()
{
	int man[MAX];
	int i, j, count = 0, n;
	printf("请输入人数n:   ", M, MAX);
	scanf("%d", &n);
	while (n<M || n>MAX)
	{
		printf("输入人数n应该位于[%d,%d]之间,请重新输入n:   ", M, MAX);
		scanf("%d", &n);
	}

	//给n个人的数组元素进行编号赋值
	for (i = 0; i < n; i++)
	{
		man[i] = i + 1;			//从1开始编号
	}

	i = 0;						//将i重新置为0开始循环
	j = 1;

	while (count < n - 1)		//只剩一个人的时候退出循环
	{

		i = i % n;				//通过对i的取模运算来进行循环
		while (man[i] == 0)
		{
			i++;
			i = i % n;
		}

		man[i] = j;
		j++;

		if (man[i] == M)
		{
			//将退出了的人的元素置为0,未退出则是非0,下一个人从1重新开始计数
			man[i] = 0;
			j = 1;
			count++;
			printf("%d号退出\n", i + 1);
		}
		else
		{
			i++;
		}
	}

	for (i = 0; i < n; i++)
	{
		if (man[i] != 0)
		{
			printf("最后留下的人为-->%d号", i + 1);
		}
	}
	printf("\n");
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是快卡黎嫩哦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值