【趣学C语言和数据结构100例】
问题描述
41.给出年、月、日,计算该日是该年的第几天解析:需要掌握函数:判断是否为闰年
42.(约瑟夫环问题)有 n 个人围成一圈,顺序排号。从第 1 个人开始报数(从 1 到 3 报数),凡报到 3 的人退出圈子,问最后留下的是原来第几号的那位,用指针+数组实现。
43.有 10 个学生,每个学生的数据包括学号,姓名,3 门课的成绩,从键盘输入 10 个学生数据。要求输出 3 门课程总平均成绩,以及最高分的学生的数据(包括学号、姓名、3 门课程成绩平均分数)。
44.采用头插法建立单链表,头插法常用于逆置
45.采用尾插法建立单链表
代码分析
==41.经典闰年==
分析:判断为该年的第几天——>则需要判断2月的天数,即判断是否为闰年。先输入年、月、日。创造数组存储月份。2月先默认28天(如果后续为闰年,则天数+1),先计算<该月的月天数所具有的天数。判断是否为闰年并且月份>=3时对天数进行++;然后输出总天数。
写一个判断闰年函数:
- 该年份能被4整除,但不能被100整除,是闰年。
- 该年份能被400整除,是闰年。
记忆:4和400可以,100不行
int leap(int year){
return year%4==0 && year%100!=0 || year%400==0;
}
==42.约瑟夫环问题==
分析:使用数组存储数据。先输入n,创造一个n大小的数组。赋初值为i+1(从1开始计数)。创造一个remain用来计数剩余人数,定义一个访问指针。只要remain剩余人数>1,就一直进行游戏。游戏开始,令p指向数组。在创造一个循环while(p!=people+n)(只要不到数组的最后一位,就一直判断,即用来遍历数组)(注意:==p是一位一位的移动,到最后一位之后,使p指向数组的开头==)游戏正式开始,如果p此时指向的不为0,就有效,则计数++;判断计数是否为3,如果为3,则计数归0,剩余人数-1,该位置赋值为0(*p=0,即退出圈子),并且进行p++。一直到remain剩余人数为1,遍历数组找到不为0的数,即最后留下的。
==43.初识结构体==
结构体的定义:
结构体知识:
//在C语言中定义:
typedef struct {
int x;
char y;
float z;
}student;
//在C++语言中定义:
struct student{
int x;
char y;
float z;
};
结构体的大小:
int+char+float=4+1+8=13
结构体定义并赋值(初始化默认为 0):
student a1;
a1.x=1;a1.y=2;a1.z=3;
student a1={
1,2,3};
分析:本题创造学号,姓名,3门课的成绩(数组),使用for循环即可解决问题。
==44.链表之头插法==
//链表知识:
//定义方式一:
typedef struct LNode {
int data;
struct LNode *next;
} LNode,*Liuklist;
//定义方式二(更优):
typedef struct LNode {
int data;
struct LNode *next;
} LNode;
typedef LNode *Liuklist;
//LNode 结构体定义了单链表节点的结构,包含 data 和 next 两个成员。
//Liuklist 被定义为指向 LNode 的指针,因此它可以用来表示单链表。
int mian(){
// 创建三个节点
LNode* node1 = (LNode*)malloc(sizeof(LNode));
LNode* node2 = (LNode*)malloc(sizeof(LNode));
LNode* node3 = (LNode*)malloc(sizeof(LNode));
// 设置节点数据
node1->data = 10;
node2->data = 20;
node3->data = 30;
// 连接节点
node1->next = node2;
node2->next = node3;
node3->next = NULL;
// 释放内存
free(node3);
free(node2);
free(node1);
return 0;
}
本题采用头插法,头插法常用于逆置
分析:返回值为指针,所以函数为Liuklist 函数名(Liuklist &L){}; (==如果链表发生变化,则加&==)
进入函数,先创建一个节点s(LNode s)用来存储要加入的数。如果L空指针, L=(Node ) malloc(sizeof (LNode)); //L是头节点,链表头节点分配内存空间,并指向空,并使L的的next指向空即L->next=NULL;输入第一个加入的数,如果不是特定的数,则开始插入。给s分配新的内存空间,令s的data为加入的数。使s的next指向L的next,而L的next指向s。(先s连接后面,防止断链)
//核心代码
s = (Lnode *)malloc(sizeof(Lnode));
s -> data=x;
s -> next=L->next;
L -> next=s;
==45.链表之尾插法==
尾插法需要找到链表的尾节点,然后将新节点插入到尾节点之后。
分析:同理,返回值为指针,所以函数为Liuklist 函数名(Liuklist &L){}; (==如果链表发生变化,则加&==)
进入函数,先创建一个节点s(LNode s)用来存储要加入的数。如果L空指针, L=(Node ) malloc(sizeof (LNode)); //L是头节点,链表头节点分配内存空间,并指向空,并使L的的next指向空即L->next=NULL;(==初始化一个r始终指向L的尾部==)输入第一个加入的数,如果不是特定的数,则开始插入。给s分配新的内存空间,令s的data为加入的数。使s的next指向r的next,而r的next指向s。令r=s,即指向最后一位。
s = (Lnode *)malloc(sizeof(Lnode));
s->data=x;
s->next=r->next;
r->next=s;
r=s;
查找尾节点的一种方法:
while (r->next != nullptr) {
r = r->next;
}
代码实现
#include <stdio.h>
int leap(int year){
return year%4==0 && year%100!=0 || year%400==0;
}
typedef struct {
int num;
char name[30];
float scare[3];
}student;
int main()
{
// 41.给出年、月、日,计算该日是该年的第几天解析:需要掌握函数:判断是否为闰年
int year,month,day,day_th;
printf("输入年月日的值:");
scanf("%d %d %d",&year,&month,&day);
int day_tab[13]={
0,31,28,31,30,31,30,31,31,30,31,30,31};
for(int i=1;i<month;i++){
day+=day_tab[i];
}
if(leap(year) && month>=3){
day++;
}
printf("是该年的第%d天",day);
//42.(约瑟夫环问题)有n个人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3 的人退出圈子,问最后留下的是原来第几号的那位,用指针实现。
int n,count=0;
printf("请输入n的值:");
scanf("%d",&n);
int people[n],remain=n,*p=NULL; //remain剩余人数
for(int i=0;i<n;i++){
people[i]=i+1; //赋初值
}
while(remain>1){
p=people;
while(p!=people+n){
if(*p!=0){
count++;
if(count==3){
*p=0;
count=0;
remain--;
}
}
p++;
}
}
for(int i=0;i<n;i++){
if(people[i]!=0){
printf("最后留下的是原来第%d号",people[i]);
}
}
//43.有 10 个学生,每个学生的数据包括学号,姓名,3门课的成绩,从键盘输人10个学生数据.要求输出3门课程总平均成绩,以及最高分的学生的数据(包括学号、姓名、3 门课程成绩平均分数)。
student stu[10];
int idex=0;
float sum=0,max_sum=0,aver_1=0,aver_2=0,aver_3=0;
for(int i=0;i<10;i++){
printf("请输入第%d个人的信息:",i+1);
scanf("%d %s %f %f %f",&stu[i].num,&stu[i].name,&stu[i].scare[1],&stu[i].scare[2],&stu[i].scare[3]);
sum=0;
for(int j=0;j<3;j++){
sum += stu[i].scare[j];
}
if(sum>max_sum){
max_sum = sum;
idex=i;
}
aver_1+=stu[i].scare[1];
aver_2+=stu[i].scare[2];
aver_3+=stu[i].scare[3];
}
aver_1 /= 10;
aver_2 /= 10;
aver_3 /= 10;
printf("3门课程总平均成绩:%.2f %.2f %.2f",aver_1,aver_2,aver_3);
printf("最高分的学生的数据:\n学号:%d 姓名:%d 3门课的成绩:%.2f %.2f %.2f",stu[idex].num,stu[idex].name,stu[idex].scare[1],stu[idex].scare[2],stu[idex].scare[3]);
// 44.采用头插法建立单链表 头插法常用与逆置
typedef struct LNode {
int data;
struct LNode *next;
} LNode;
typedef LNode *Liuklist;
//LNode 结构体定义了单链表节点的结构,包含 data 和 next 两个成员。Liuklist 被定义为指向 LNode 的指针,因此它可以用来表示单链表。
Liuklist list_Headiusert(Liuklist &L) {
//改结构加&
LNode *s; // 加入s
int x; //s的值
L=(Node *) malloc(sizeof (LNode)); //L是头节点,链表头节点分配内存空间,并指向空
L->next=NULL;
printf("请输入数据(输入9999结束): ");
scanf("%d",&x);
while (x!=9999) {
s = (Lnode *)malloc(sizeof(Lnode));
s -> data=x;
s -> next=L->next;
L -> next=s;
printf("请输入数据(输入9999结束): ");
scanf("%d", &x);
if (x == 9999) {
break;
}
}
return L;
}
// 45.采用尾插法建立单链表
Liuklist list_Tailiusert(Liuklist &L) {
//改结构加&
LNode *s,*r;
int x;
L=(Node *) malloc(sizeof (LNode));
L->next=NULL;
r=L;
printf("请输入数据(输入9999结束): ");
scanf("%d",&x);
while (x!=9999) {
s = (Lnode *)malloc(sizeof(Lnode));
s->data=x;
s->next=r->next;
r->next=s;
r=s;
printf("请输入数据(输入9999结束): ");
scanf("%d", &x);
if (x == 9999) {
break;
}
}
return L;
}
return 0;
}
总结
本文介绍了五个数据结构问题及其C语言实现,这些问题涉及日期计算、约瑟夫环问题、学生成绩处理、以及单链表的头插法和尾插法操作。这些算法问题覆盖了基础算法、数组、指针、结构体和链表的多个方面,展示了数据结构在解决实际问题中的应用。
日期计算问题要求我们根据给定的年、月、日计算该日是该年的第几天。这个问题的解决关键在于判断是否为闰年,并根据月份累加天数。
约瑟夫环问题是一个经典的递归问题,要求我们找出在特定报数规则下最后留下的人的编号。这个问题的解决可以通过模拟报数过程,使用数组和指针来实现。
学生成绩处理问题要求我们输入10个学生的数据,并计算输出3门课程的总平均成绩以及最高分学生的信息。这个问题的解决涉及到结构体的使用,以及对数组和结构体成员的操作。
单链表的头插法和尾插法问题是链表操作的基础,头插法常用于逆置链表,而尾插法则需要找到链表的尾部进行插入。这两个问题的解决展示了链表操作的灵活性和多样性。
这些算法的实现不仅展示了C语言在处理数组、指针和链表时的能力,也体现了算法设计的基本思想,如条件判断、循环控制和递归。通过这些算法的学习,我们可以更好地理解数据结构和算法的基本概念,提高解决实际问题的能力。
总的来说,这些算法问题不仅锻炼了编程能力,也加深了对数据结构和算法的理解。通过这些问题的解决,我们可以逐步提高自己的编程技能,为将来的学习和工作做好准备。这些算法的掌握对于计算机专业的学生和软件开发人员来说都是非常重要的。通过这些练习,我们可以逐步提高自己的编程技能,为将来的学习和工作做好准备。同时,这些问题的解决也体现了算法在处理数据时的灵活性和效率,为我们在实际开发中遇到类似问题提供了解决思路。