文章目录
0x00 前言
0x01 百鸡百钱
0x1 题目描述
0x2 问题分析
0x3 代码设计
0x4 完整代码
0x5 运行效果
0x6 举一反三 [兔鸡百钱]
0x02 借书方案知多少
0x1 题目描述
0x2 问题分析
0x3 代码设计
0x4 完整代码
0x5 运行效果
0x6 举一反三 [领导小组方案]
0x03 打鱼还是晒网
0x1 题目描述
0x2 问题分析
0x3 代码设计
0x4 完整代码
0x5 运行效果
0x04 兔子生兔子
0x1 题目描述
0x2 问题分析
0x3 代码设计
0x4 完整代码
0x5 运行效果
0x05 密码解锁
0x1 题目描述
0x2 问题分析
0x3 代码设计
0x4 完整代码
0x5 运行效果
0x06 最佳存款方案
0x1 题目描述
0x2 问题分析
0x3 代码设计
0x4 完整代码
0x5 运行效果
0x07 牛顿迭代法
0x1 题目描述
0x2 问题分析
0x3 代码设计
0x4 完整代码
0x5 运行效果
0x08 持续更新···
0x09 参考文献
0x10 总结
0x00 前言
写这篇《C语言笔记 | 数据结构入门指南》主要是为了帮助更多的编程爱好者打开数据结构的大门,同时也是为了自我编程水平能力的提升。在深奥的数据结构领域中,这篇入门指南就像海上的一叶扁舟。虽是虚无缥缈,但是总比什么都没有要好得多。我将竭尽我所能,简明扼要地解释相关案例中的知识点。其中不乏会有错误,恳请各位老师不吝指正。
文章来源:https://www.toymoban.com/news/detail-472485.html
0x01 百鸡百钱
0x1 题目描述
我国古代数学家张丘建在《算经》一书中提出的数学问题:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?
0x2 问题分析
关于百鸡百钱的不定方程组:
其中, x 表示鸡翁、 y 表示鸡母、 z 表示鸡雏。在计算机中,我们可以通过使用计算机思维对这类题目计算,而不是数学思维。可以使用穷举的方法将每个结果列举出来,直到计算机找出哪个正确的结果。也就是怎么买可以做到百鸡百钱。
0x3 代码设计
int x, y, z;
代码解析:定义三个变量, x 表示鸡翁、 y 表示鸡母、 z 表示鸡雏。
for(x = 0; x <= 20; x++)
{
for(y = 0; y <= 33; y++)
{
z = 100 - (x + y);
代码解析:这里可以使用三重循环,但是鸡雏可以直接通过 100 减去鸡翁和鸡母的和来确定。减少一个循环可以起到代码优化的效果。第一个循环用来确定鸡翁的数量,第二个循环用来确定鸡母的数量。
if((5 * x + 3 * y + z / 3) == 100)
{
printf("鸡翁:%2d | 鸡母 :%2d | 鸡雏:%2d\n", x, y, z);
}
代码解析: 使用 if 判断语句判断,如果不定方程组的第二个式子的值等于 100 ,那么就执行一次 printf 输出函数记录一次百鸡百钱的值。
0x4 完整代码
#include<stdio.h>
int main()
{
int x, y, z;
for(x = 0; x <= 20; x++)
{
for(y = 0; y <= 33; y++)
{
z = 100 - (x + y);
if((5 * x + 3 * y + z / 3) == 100)
{
printf("鸡翁:%2d | 鸡母 :%2d | 鸡雏:%2d\n", x, y, z);
}
}
}
return 0;
}
0x5 运行效果
鸡翁: 0 | 鸡母 :25 | 鸡雏:75
鸡翁: 3 | 鸡母 :20 | 鸡雏:77
鸡翁: 4 | 鸡母 :18 | 鸡雏:78
鸡翁: 7 | 鸡母 :13 | 鸡雏:80
鸡翁: 8 | 鸡母 :11 | 鸡雏:81
鸡翁:11 | 鸡母 : 6 | 鸡雏:83
鸡翁:12 | 鸡母 : 4 | 鸡雏:84
--------------------------------
Process exited after 0.08475 seconds with return value 0
请按任意键继续. . .
0x6 举一反三 [兔鸡百钱]
题目描述
河伯有财富百金,欲以百金买百禽。鸡一只计二钱,兔一只计三钱。若购三兔,则赠鸡一只。请推算河伯所购百禽之中,鸡之数量和兔之脚数,共计几何?(一只鸡足为二,一只兔脚为四)
问题分析
关于兔鸡百钱的线性方程:
其中, r 表示兔子、 c 表示鸡。解法和百鸡百钱问题一样,可以把送的鸡稍后再计算,先判断买兔子,最后在输出函数中判断即可。如果买了 3 只兔子就加 1 个鸡。我们不用特殊计算它,因为我们先计算了兔子,假如我们买了 4 只兔子,那么计算鸡的数量就可以是 4 除 3 。
代码设计
int r, c;
代码解析:定义两个变量, r 表示兔子的缩写, c 表示鸡的缩写。
for (r = 0; r <= 33; r++)
{
for (c = 0; c <= 50; c++)
{
if ((3 * r + 2 * c) == 100)
{
printf("兔脚:%4d | 鸡足:%4d\n", r * 4, (c + r / 3) * 2);
}
}
}
代码解析:使用双重 for 循环易于理解,先循环兔子的数量,接着循环鸡的数量,给一个双重循环的判断条件,如果 3r + 2c 个家禽满足 100 钱。那么则记录这次的结果。题目要求是就算鸡脚和兔脚。所以将兔子数量乘 4 就是兔脚数量。鸡脚数量是乘 2 ,不过我们还需要将赠送的鸡一同计算。赠送的鸡可以表示为兔子总数除 3 。
完整代码
#include <stdio.h>
int main()
{
int r, c;
for (r = 0; r <= 33; r++)
{
for (c = 0; c <= 50; c++)
{
if ((3 * r + 2 * c) == 100)
{
printf("兔脚:%4d | 鸡足:%4d\n", r * 4, (c + r / 3) * 2);
}
}
}
return 0;
}
运行效果
兔脚: 0 | 鸡足: 100
兔脚: 8 | 鸡足: 94
兔脚: 16 | 鸡足: 90
兔脚: 24 | 鸡足: 86
兔脚: 32 | 鸡足: 80
兔脚: 40 | 鸡足: 76
兔脚: 48 | 鸡足: 72
兔脚: 56 | 鸡足: 66
兔脚: 64 | 鸡足: 62
兔脚: 72 | 鸡足: 58
兔脚: 80 | 鸡足: 52
兔脚: 88 | 鸡足: 48
兔脚: 96 | 鸡足: 44
兔脚: 104 | 鸡足: 38
兔脚: 112 | 鸡足: 34
兔脚: 120 | 鸡足: 30
兔脚: 128 | 鸡足: 24
--------------------------------
Process exited after 0.03176 seconds with return value 0
请按任意键继续. . .
0x02 借书方案知多少
0x1 题目描述
小明有 5 本新书,要借给 A 、 B 、 C 三位小朋友,若每人每次只能借 1 本,则可以有多少种不同的借法?
0x2 问题分析
这题关于排列组合,也就是计算 5 个数中 3 个不同数的所有排列方法,那么可以先进行编号 1~5 表示这五本不同的书,接着定义三个变量 a 、 b 、 c 表示三个小朋友。那么可以使用循环嵌套的方法让每个小朋友进行选书,在 a 和 b 之间判断不能选一样的书。接着让 a 和 c 以及 b 和 c 他们之间也不能选择一样的书。
0x3 代码设计
int a, b, c, i = 0;
代码解析:定义一个变量 a 表示小朋友 A 、变量 b 表示小朋友 B 、变量 c 表示小朋友 C 。定义 i = 0 用来累计有多少种不同的借法。
for(a = 1; a <= 5; a++)
{
for(b = 1; b <= 5; b++)
{
if(a != b)
{
for(c = 1; c <= 5; c++)
{
if(a != c && b != c)
{
i++;
printf("a:%d | b:%d | c:%d\n", a, b, c);
}
}
}
}
}
代码解析:第一层循环用来计算小朋友 A 拿的书,第二层循环计算小朋友 B 拿的书。给出判断条件,如果 a 不等于 b 则执行以下代码,就是判断如果小朋友 A 和小朋友 B 拿了一样的书就是没有意义的,则不执行。接着给第三层循环,用来计算小朋友 C 。判断如果 A 和 C 拿了一样的书或者是 B 和 C 拿了一样的书,那么代码不执行。如果都不是一样的书则会执行 i++ 累加器用来计算有多少种分配的次数,并打印结果显示这次小朋友 A 、 B 、 C 是拿的什么书。
printf("借法:%d", i);
代码解析:使用 printf 函数输出变量 i 累加的值,输出的结果就是借法的次数。
0x4 完整代码
#include<stdio.h>
int main()
{
int a, b, c, i = 0;
for(a = 1; a <= 5; a++)
{
for(b = 1; b <= 5; b++)
{
if(a != b)
{
for(c = 1; c <= 5; c++)
{
if(a != c && b != c)
{
i++;
}
}
}
}
}
printf("借法:%d", i);
return 0;
}
0x5 运行效果
借法:60
--------------------------------
Process exited after 0.08041 seconds with return value 0
请按任意键继续. . .
0x6 举一反三 [领导小组方案]
题目描述
一家公司有 25 名员工。为了更好的管理公司,于是河伯决定将 4 名员工选为领导小组成员,问有多少种不同的选法?
问题分析
这题关于排列组合,也就是计算 25 个数中 4 个不同数的所有排列方法,除了用计算机思维,这题用数学思维会更便捷。
关于领导小组方案的组合公式:
代码设计
int a;
代码解析:定义一个变量 a 用来存储组合公式的结果。
a = (25 * 24 * 23 * 22) / (1 * 2 * 3 * 4);
代码解析: 直接计算组合公式保存数据给变量 a 。
printf("方案:%d", a);
代码解析: 使用 printf 函数输出变量 a 中存储的值,输出的结果就是方案的次数。
完整代码
#include <stdio.h>
int main()
{
int a;
a = (25 * 24 * 23 * 22) / (1 * 2 * 3 * 4);
printf("方案:%d\n", a);
return 0;
}
运行效果
方案:12650
--------------------------------
Process exited after 0.028 seconds with return value 0
请按任意键继续. . .
0x03 打鱼还是晒网
0x1 题目描述
中国有句俗语叫 “三天打鱼两天晒网” 。某人从2000年1月1日起便开始 “三天打鱼两天晒网” ,问这个人在以后的某一天中是“打鱼”还是“晒网”。
0x2 问题分析
先获取用户输入的年月日,使用一个函数用来验证闰年。验证方法是:四年一润,百年不润。四百年一润。根据方法建立规则并返回即可。循环遍历年份,从 2000 开始。如果是闰年就加 366 天,如果是平年加 365 天。然后计算月份,定义一个数组,里面有 1-12 月份的天数,给一个判断条件,如果最后一年是闰年,就修改数组的值为 29 。然后用一个循环将月份累加起来。注意:累加月份时,最后一月份不计算,应该在天数中进行计算。
0x3 代码设计
int L(int Y)
{
return (Y % 4 == 0 && Y % 100 != 0) || (Y % 400 == 0);
}
代码解析: 定义一个函数,用来判断闰年。返回值就是判断润年的方法,如果不是润年就没有返回值。
int y, m, d, i, j = 0;
代码解析: 变量 y 表示年份,变量 m 表示月份,变量 d 表示天数。变量 i 表示循环中的计数。变量 j 则是计算天数的累加和,因为要进行计数,需要先将数值 j 归零。
int k[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
代码解析: 定义一个 k 数组,里面存放 1-12 月份的天数。
scanf("%d %d %d", &y, &m, &d);
代码解析: 获取用户输入年、月、日。
for(i = 2000; i < y; i++)
{
j += L(i) ? 366 : 365;
}
代码解析: 使用 for 循环从 2000 年开始计算,到用户输入的数之前一年结束。因为最后一年由后面月份完成。表达式使用 j 进行累加,调用润年判断函数,通过三目运算判断,如果是闰年则加 366 ,否则加 365 。
if(L(y))
{
k[1] = 29;
}
代码解析: 矫正数组中的数据,判断最后一年是否为闰年,如果是闰年则修改二月份的数据为 29 。
for (i = 1; i < m; i++)
{
j += k[i];
}
j += d;
代码解析: 使用 for 循环累加月份,到最后一月之前结束,同样的最后一月通过天数计算。表达式中使用 j 累加数组中的数据。接着后面使用 j 累加最后一个天数的值。
if (j % 5 == 1 || j % 5 == 2 || j % 5 == 3)
{
printf("今天要努力\n");
}
else
{
printf("偶尔摸会鱼\n");
}
代码解析: 使用 if 判断,三个条件中达成一个就输出 “今天要努力” 。因为三天打鱼两天晒网,所以模余运算时,结果为 1-3 时说明今天是打鱼日。否则输出偶尔摸会鱼。
0x4 完整代码
#include <stdio.h>
int L(int Y)
{
return (Y % 4 == 0 && Y % 100 != 0) || (Y % 400 == 0);
}
int main()
{
int y, m, d, i, j = 0;
int k[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
scanf("%d %d %d", &y, &m, &d);
for(i = 2000; i < y; i++)
{
j += L(i) ? 366 : 365;
}
if(L(y))
{
k[1] = 29;
}
for (i = 1; i < m; i++)
{
j += k[i];
}
j += d;
if (j % 5 == 1 || j % 5 == 2 || j % 5 == 3)
{
printf("今天要努力\n");
}
else
{
printf("偶尔摸会鱼\n");
}
return 0;
}
0x5 运行效果
2023 06 05
今天要努力
--------------------------------
Process exited after 2.524 seconds with return value 0
请按任意键继续. . .
0x04 兔子生兔子
0x1 题目描述
有一对兔子,从出生后的第 3 个月起每个月都生一对兔子。小兔子长到第 3 个月后每个月又生一对兔子,假设所有的兔子都不死,问 10 个月内每个月的兔子总对数为多少?
0x2 问题分析
关于兔子生兔子得出以下规律:
month | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
rabbit | 2 | 2 | 4 | 6 | 10 | 16 | 26 | 42 | 68 | 110 |
这种题目可以使用函数递归的方法会更清晰易懂,题目的原型是斐波那契数列。
0x3 代码设计
int r(int n)
{
if(n < 3)
{
return 2;
}
else
{
return r(n - 1) + r(n - 2);
}
}
代码解析:定义一个函数用来计算兔子每个月的总数,这个函数可以判断 n 如果小于三,就说明是兔子在前三个月,那么返回 2 表示两只兔子。如果大于三,假设用户输入的数为 5 ,那么执行 (n - 1) + (n - 2) ,表示执行前一项的 n 加上前两项的 n 。注意: n 的数据可以被保留,而不是 1,2,3 。前一项表示 4 - 1,前两项表示 4 - 2 。[2,2,4,6],可以看出第四个数减一就是第三位为 4 ,第四位减去二就是第二位。相加就是 6 。
int main()
{
int n, i;
scanf("%d", &n);
for(i = 1; i <= n; i++)
{
r(i);
printf("%d\t", r(i));
}
return 0;
}
代码解析:在主函数中定义一个变量 n 用来获取用户输入,使用一个 for 循环来循环遍历用户输入的数,从 1 开始。在循环体中调用函数,并打印当前的结果。
0x4 完整代码
#include<stdio.h>
int r(int n)
{
if(n < 3)
{
return 2;
}
else
{
return r(n - 1) + r(n - 2);
}
}
int main()
{
int n, i;
scanf("%d", &n);
for(i = 1; i <= n; i++)
{
r(i);
printf("%d\t", r(i));
}
return 0;
}
0x5 运行效果
10
2 2 4 6 10 16 26 42 68 110
--------------------------------
Process exited after 0.7153 seconds with return value 0
请按任意键继续. . .
0x05 密码解锁
0x1 题目描述
有一个密码锁,需要输入四位数字密码才能打开。但是密码被人忘记了,只记得一些线索。甲说:这个密码的前两位数字是相同的;乙说:这个密码的后两位数字是相同的,但与前两位不同;丙是数学家,他说:这个密码刚好是一个整数的平方。请根据以上线索找出密码。
0x2 问题分析
根据题目描述进行以下分析:
规则一:密码前两位数值相同,设为 aa |
规则二:密码后两位数值相同,设为 bb |
规则三:aabb 的平方根是整数,且(aa ≠ bb) |
根据规则描述,这里的思路是使用双重循环分别枚举出 aa 以及 bb 所有的数值,然后计算 aabb 的平方根是否是整数,如果是整数则输出这个密码。
0x3 代码设计
int i, j, n, s;
代码解析:定义一个变量 i 和 j 用来执行双重循环,定义变量 n 用于后续将前两位数和后两位数进行相加。变量 s 用于存储计算的平方根的值。
for(i = 1; i <= 9; i++)
{
for(j = 1; j <= 9; j++)
{
...
}
}
代码解析:外循环表示前两个数的循环周期,内循环表示后两个数的循环周期。外循环执行一次,内循环执行一轮。
n = i * 1100 + j * 11;
s = sqrt(n);
if(s * s == n)
{
printf("车牌号:%d", n);
}
代码解析:在内循环中执行每一次循环的计算,计算 aabb 的值保存给变量 n 。使用 sqrt 函数计算 aabb 的平方根。使用 if 进行判断,如果 s 的平方等于 n 的值,说明这个数是整数,符合规则三的条件,那么使用 printf 函数输出这个密码。
0x4 完整代码
#include<stdio.h>
#include<math.h>
int main()
{
int i, j, n, s;
for(i = 1; i <= 9; i++)
{
for(j = 1; j <= 9; j++)
{
n = i * 1100 + j * 11;
s = sqrt(n);
if(s * s == n)
{
printf("密码:%d", n);
}
}
}
return 0;
}
0x5 运行效果
密码:7744
--------------------------------
Process exited after 0.01944 seconds with return value 0
请按任意键继续. . .
0x06 最佳存款方案
0x1 题目描述
假设银行一年整存零取的月息为 0.55% 。现在某人手中有一笔钱,他打算在今后 5 年中的每年年底取出 1000 元,到第 5 年时刚好取完,请算出他存钱时应存入多少。
0x2 问题分析
根据题目描述给出存钱公式:
存钱公式 (1000 + s) / (1 + 12 * 0.0055) 可以解释为每年存入1000 元,并在每个月的利率为0.55%的情况下计算存款总额。在每次循环中,上一年的存款总额将与新存入的 1000 元相加,然后除以年利率调整系数 (1 + 12 * 0.0055) 。重复五次循环后,计算出最终的存钱总金额。
0x3 代码设计
int i;
float s;
代码解析:定义整数型变量 i 用于循环中的执行次数,定义浮点型变量 s 用于存储循环体中的数据。
for(i = 1; i <= 5; i++)
{
s = (1000 + s) / (1 + 12 * 0.0055);
}
代码解析:循环五次表示五年,循环体中进行逆推,第五年年初就是 1000/(1+12×0.0055) ,第四年年初就是 (1000 + s) / (1 + 12 * 0.0055) ,其中 s 表示第五年年初的钱。那么第三年就是第四年年初的钱加上 1000 后并计算利润率,以此类推。
printf("存钱数:%.2f", s);
代码解析:输出存钱时要存的数量,使用 .2f 的方法保留两位小数。
0x4 完整代码
#include<stdio.h>
int main()
{
int i;
float s;
for(i = 1; i <= 5; i++)
{
s = (1000 + s) / (1 + 12 * 0.0055);
}
printf("存钱数:%.2f", s);
return 0;
}
0x5 运行效果
存钱数:4144.49
--------------------------------
Process exited after 0.03463 seconds with return value 0
请按任意键继续. . .
0x07 牛顿迭代法
0x1 题目描述
用 Newton 迭代法求方程 ,在 附近的根。
0x2 问题分析
根据牛顿迭代法,迭代公式为:
解:
令,
把 代入
对方程两边同时求导,得:
table:
0 1.41176 -0.72707
1 1.62424 -0.14549
2 1.69230 -0.01316
已知初始猜测值为 1 ,将 1 代入牛顿迭代公式:
第 1 次迭代:
第 2 次迭代:
0x3 代码设计
double f(double x, double a, double b, double c, double d)
{
return a * pow(x, 3) + b * pow(x, 2) + c * x + d;
}
代码解析:定义一个双精度的函数 f ,用于计算方程的表达式。
double F(double x, double a, double b, double c)
{
return 3 * a * pow(x, 2) + 2 * b * x + c;
}
代码解析:定义一个双精度函数 F ,用于计算这个方程表达式的导数。
int main()
{
int k;
double a, b, c, d, x = 1.0, fx; #--x的猜测值--
scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
printf("k\t xk\t\t f(xk)\n");
for (k = 0; k <= 5; k++)
{
fx = f(x, a, b, c, d);
printf("%d\t %lf\t %lf\n", k, x, fx);
x = x - fx / F(x, a, b, c);
}
return 0;
}
代码解析:使用 scanf 函数获取用户输入,使用 printf 函数打印标题 k 、 xk 、f(xk) 。用 for 循环执行迭代,设 k 为 0 ,循环 6 次。将函数表达式计算的结果保存在 fx 中。使用 printf 函数输出第一次迭代的结果。根据牛顿迭代公式更新 x 的猜测值,也就是 x - fx / F(x,a,b,c) 。
0x4 完整代码
#include <stdio.h>
#include <math.h>
double f(double x, double a, double b, double c, double d)
{
return a * pow(x, 3) + b * pow(x, 2) + c * x + d;
}
double F(double x, double a, double b, double c)
{
return 3 * a * pow(x, 2) + 2 * b * x + c;
}
int main()
{
int k;
double a, b, c, d, x = 1.0, fx;
scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
printf("k\t xk\t\t f(xk)\n");
for (k = 0; k <= 5; k++)
{
fx = f(x, a, b, c, d);
printf("%d\t %lf\t %lf\n", k, x, fx);
x = x - fx / F(x, a, b, c);
}
return 0;
}
0x5 运行效果
1 -7.7 19.2 -15.3
k xk f(xk)
0 1.000000 -2.800000
1 1.411765 -0.727071
2 1.623242 -0.145493
3 1.692300 -0.013168
4 1.699910 -0.000151
5 1.700000 -0.000000
--------------------------------
Process exited after 5.78 seconds with return value 0
请按任意键继续. . .
0x08 持续更新···
进制转换 |
0x09 参考文献
[1].百度百科. 百鸡百钱[EB/OL]. [2023-05-29]. https://baike.baidu.com/item/%E7%99%BE%E9%B8%A1%E7%99%BE%E9%92%B1.
[2].刘河飞, 闰凯峰. 趣学Python算法100例[M]. ISBN:978-7-111-66598-4. 北京: 机械工业出版社, 2020.9.
0x10 总结
文章内容为学习记录的笔记,由于作者水平有限,文中若有错误与不足欢迎留言,便于及时更正。文章来源地址https://www.toymoban.com/news/detail-472485.html
到了这里,关于C语言笔记 | 数据结构入门指南的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!