精品推荐:
《征服数据结构》专栏:50多种数据结构彻底征服
《经典图论算法》专栏:50多种经典图论算法全部掌握
001, 组无重复数字的数
题目:有 1、2、3、4 四个数字,能组成多少个互不相同且无重复数字的三位数?
问题分析:先在百位数选择一个数字,接着在十位上选择一个数字,最后在个位上选择一个数字,但要保证每次选择的三个数字都互不相同,使用三个for循环即可找出这样的数字。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h> // 标准的输入输出头文件
int main() {
for (int i = 1; i < 5; i++) { // 先选择百位上的数字
for (int j = 1; j < 5; j++) {// 接着选择十位上的数字
for (int k = 1; k < 5; k++) { // 最后选择个位上的数字
// 选择的三个数字必须都互不相同
if (i != j && i != k && j != k) {
printf("%d%d%d\n", i, j, k);
}
}
}
}
return 0;
}
优化:上面代码中也可以在for循环的时候判断是否有重复的数字,如果有,则直接跳过。
运行结果:
123
124
132
134
142
143
213
214
231
234
241
243
312
314
321
324
341
342
412
413
421
423
431
432
002,企业发放的奖金根据利润提成
利润 i 低于或等于10万元时,奖金可提10%;
利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%;
20万到40万之间时,高于20万元的部分,可提成5%;
40万到60万之间时高于40万元的部分,可提成3%;
60万到100万之间时,高于60万元的部分,可提成1.5%;
高于100万元时,超过100万元的部分按1%提成。
从键盘输入当月利润 i ,求应发放奖金总数?
问题分析:根据利润的区间,让数字在不同的区间分别单独计算。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
double i;// 利润
double bonus = 0;// 奖金
printf("当月利润是:");
scanf("%lf", &i);// 输入当月利润
double bonus1 = 100000 * 0.1;// 十万的奖金
double bonus2 = bonus1 + 100000 * 0.075;// 二十万的奖金
double bonus4 = bonus2 + 200000 * 0.05;// 四十万的奖金
double bonus6 = bonus4 + 200000 * 0.03;// 六十万的奖金
double bonus10 = bonus6 + 400000 * 0.015;// 一百万的奖金
if (i <= 100000) {
// 利润 i 低于或等于10万元时,奖金可提10%;
bonus = i * 0.1;
} else if (i <= 200000) {
// 低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%;
bonus = bonus1 + (i - 100000) * 0.075;
} else if (i <= 400000) {
// 20万到40万之间时,高于20万元的部分,可提成5%;
bonus = bonus2 + (i - 200000) * 0.05;
} else if (i <= 600000) {
// 40万到60万之间时高于40万元的部分,可提成3%;
bonus = bonus4 + (i - 400000) * 0.03;
} else if (i <= 1000000) {
// 60万到100万之间时,高于60万元的部分,可提成1.5%;
bonus = bonus6 + (i - 600000) * 0.015;
} else if (i > 1000000) {
// 高于100万元时,超过100万元的部分按1%提成。
bonus = bonus10 + (i - 1000000) * 0.01;
}
printf("应发奖金为:bonus=%lf", bonus);
return 0;
}
运行结果:
当月利润是:350000
应发奖金为:bonus=25000.000000
003,完全平方数
题目:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?
问题分析:
假设该数为 x。
1、则 x + 100 = m,x + 100 + 168 = n,其中 m 和 n 都是完全平方数。
2、设 n = a2,m = b2,则 n - m = (a + b)(a - b) = 168,因为a+b和a-b具有相同的奇偶性,又因为168是偶数,所以a+b和a-b都是偶数。
3、设 a+b=2*i,a-b=2*j;可得 i * j = 168/4=42。
4、接下来只需要枚举 i 从 1 到 42 即可,根据上面的公式我们也可以得出 a = i + j,b = i - j,进一步又可以得出 m ,n 以及 x 的值。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int main() {
// 枚举 i 从 1 到 42 。
for (int i = 1; i <= 42; i++) {
if (42 % i == 0) { // 要满足i*j=42
int j = 42 / i; // 计算 j 的值。
if (i > j) {
// 根据 i 和 j 可以计算 a ,b 以及 x 的值。
int a = i + j;
int b = i - j;
int x = b * b - 100;
printf("%d + 100 = %d * %d\n", x, b, b);
printf("%d + 268 = %d * %d\n", x, a, a);
}
}
}
return 0;
}
运行结果:
+ 100 = 1 * 1
+ 268 = 13 * 13
21 + 100 = 11 * 11
21 + 268 = 17 * 17
261 + 100 = 19 * 19
261 + 268 = 23 * 23
1581 + 100 = 41 * 41
1581 + 268 = 43 * 43
004,判断当天是这一年的第几天
题目:输入某年某月某日,判断这一天是这一年的第几天?
问题分析:先计算当月之前的总天数,然后再加上当月的天数。比如10月16号,先计算9月(包含9月)之前的总天数,然后加上10月的16天,最后在判断是否是闰年,如果是闰年并且输入的月份大于 2 ,要多加一天。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int main() {
// 每月的天数,其中2月先暂定为28天。
const int daysInMonth[] = {31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
int day, month, year, total;
printf("请输入年月日,格式为:年,月,日(2024,10,16)\n");
scanf("%d,%d,%d", &year, &month, &day); // 格式为:2024,10,16
total = 0; // 计算输入月份之前的总天数
for (int i = 0; i < month - 1; i++)
total += daysInMonth[i];
total += day;// 加上当月的天数
// 判断是否为闰年
int leap = (year % 400 == 0) ||
(year % 4 == 0 && year % 100 != 0);
// 如果是闰年且月份大于2, 总天数加一天
if (leap && month > 2)
total++;
printf("这是这一年的第 %d 天。", total);
return 0;
}
运行结果:
请输入年月日,格式为:年,月,日(2024,10,16)
2024,10,16
这是这一年的第 290 天。
005,三个数由小到大输出
题目:输入三个整数 x、y、z,请把这三个数由小到大输出。
问题分析:先用 x 和 y ,z 比较,只要比它俩小就交换,这样就可以保证 x 是这三个数中最小的。然后用 y 和 z 比较,把最大值保存在 z 中,这样 x、y、z 就是从小到大的了。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include <stdio.h>
// 交换两个变量的值
void swap(int *a, int *b) {
int tmp = *a;// 需要临时变量
*a = *b;
*b = tmp;
}
int main() {
int x, y, z;
printf("请输入三个数字:\n");
scanf("%d,%d,%d", &x, &y, &z);// 注意输入的时候用逗号隔开
// 两两比较,前两个if可以保证 x 最小,最后一个if可以保证 z 最大。
if (x > y)
swap(&x, &y);
if (x > z)
swap(&x, &z);
if (y > z)
swap(&y, &z);
printf("从小到大排序: %d %d %d\n", x, y, z);
return 0;
}
运行结果:
请输入三个数字:
3,7,6
从小到大排序: 3 6 7
006,输出字母C图案
题目:用 * 号输出字母C的图案。
问题分析:按照字母C的形状直接输出即可。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int main() {
printf("用 * 号输出字母 C!\n");
printf("****\n");
printf("*\n");
printf("* \n");
printf("****\n");
return 0;
}
运行结果:
用 * 号输出字母 C!
****
*
*
****
007,特殊图案
题目:输出特殊图案。
问题分析:不同字符,图形不一样。需要把编码格式改成437 OEM-美国,否则会出现乱码。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#include <windows.h> // 引用头文件
int main() {
SetConsoleOutputCP(437);// 设置编码为437 OEM-美国
char a = 177, b = 223;// 随便两个数字
printf("%c%c%c%c%c\n", b, a, a, a, b);
printf("%c%c%c%c%c\n", a, b, a, b, a);
printf("%c%c%c%c%c\n", a, a, b, a, a);
printf("%c%c%c%c%c\n", a, b, a, b, a);
printf("%c%c%c%c%c\n", b, a, a, a, b);
return 0;
}
运行结果:
008,9*9 乘法表
题目:输出 9*9 口诀。
问题分析:使用两个for循环即可完成。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int main() {
for (int i = 1; i < 10; i++) {// 行
for (int j = 1; j <= i; j++) { // 列
// %-3d表示左对齐,占3位
printf("%d*%d=%-3d", j, i, i * j);
}
printf("\n"); // 换行
}
return 0;
}
运行结果:
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
009,国际象棋棋盘
题目:要求输出国际象棋棋盘。
问题分析:国际象棋棋盘由64个黑白相间的格子组成,分为8行*8列。用 i 控制行, j 来控制列,根据 i+j 的和来控制输出黑方格,还是白方格。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#include <windows.h> // 引用头文件
int main() {
SetConsoleOutputCP(437);// 设置编码为437 OEM-美国
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++)
if ((i + j) % 2 == 0)
printf("%c%c", 219, 219);// 白色
else
printf(" ");// 黑色
printf("\n");// 换行
}
return 0;
}
运行结果:
010,打印笑脸
题目:打印楼梯,同时在楼梯上方打印两个笑脸。
问题分析:用 ASCII 1 输出笑脸;用 i 和 j 来控制行和列,然后输出白色当做楼梯,要注意需要修改编码格式。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#include <windows.h> // 引用头文件
int main() {
SetConsoleOutputCP(437);// 设置编码为437 OEM-美国
printf("\1\1\n"); // 打印两个笑脸
for (int i = 1; i < 10; i++) {
for (int j = 1; j <= i; j++)
printf("%c%c", 219, 219);// 打印白色楼梯
printf("\n");// 换行
}
return 0;
}
运行结果:
011,兔子生崽
题目:古典问题(兔子生崽):有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?(输出前40个月即可)
问题分析:兔子的规律为1,1,2,3,5,8,13,21....,即下个月是上两个月之和,这是一个典型的斐波那契数列。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
int a = 1, b = 1;// 前两项
printf("%12d%12d", a, b); // 输出前两项,%12d表示占12行,右对齐。
for (int i = 3; i <= 40; i++) {// 从第3项开始计算
int cur = a + b;// 当前月是上两个月之和
a = b;
b = cur;
printf("%12d", cur);// 打印当前月的值
if (i % 4 == 0)// 输入4个换行
printf("\n");
}
return 0;
}
运行结果:
1 1 2 3
5 8 13 21
34 55 89 144
233 377 610 987
1597 2584 4181 6765
10946 17711 28657 46368
75025 121393 196418 317811
514229 832040 1346269 2178309
3524578 5702887 9227465 14930352
24157817 39088169 63245986 102334155
012,101到200的素数
题目:判断 101 到 200 之间的素数。
问题分析:101 到 200之间的偶数不可能是素数,所以我们只需要判断奇数即可。对于每一个奇数,判断能不能被 2 到 sqrt(包含这个数)之间的数整除,如果能被整除,则表明此数不是素数,否则是素数。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
// 判断101 到 200之间的奇数是否是素数。
bool isPrime(int num) {
int sq = (int) sqrt(num);// 计算平方根
for (int j = 2; j <= sq; j++) {
if (num % j == 0)// 如果能被 j 整除,则不是素数。
return false;
}
return true;
}
int main() {
int count = 0;// 统计素数的个数
printf("素数在 101 到 200 之间的列表:\n");
// 101 到 200之间的偶数不可能是素数,所以我们只需要判断奇数即可。
for (int i = 101; i <= 200; i += 2) {
if (isPrime(i)) { // 如果是素数,则打印
printf("%d ", i);
if (++count % 5 == 0)// 每 5 个换行
printf("\n");
}
}
return 0;
}
运行结果:
101 到 200 之间的列表:
101 103 107 109 113
127 131 137 139 149
151 157 163 167 173
179 181 191 193 197
199
013,水仙花数
题目:打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身。例如:153是一个"水仙花数",因为153=1^3+5^3+3^3=1+125+27。
问题分析:对于100-999之间的每一个数,分别求出个位,十位,百位,然后计算它们的立方之和是否等于该数本身,如果等于,则是水仙花数,否则不是。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int main() {
int i, x, y, z;
for (i = 100; i < 1000; i++) {
x = i % 10;// 个位
y = i / 10 % 10;// 十位
z = i / 100;// 百位
if (i == x * x * x + y * y * y + z * z * z)
printf("%d\n", i);
}
return 0;
}
运行结果:
153
370
371
407
014,分解质因数
题目:将一个正整数分解质因数。例如:输入 90,打印出 90=2*3*3*5。
问题分析:对于输入的整数n ,判断 2 到 n 之间哪些数能被它整除,如果能被正常,则一直除。比如 120 能被 2 整除,结果是 60 ,60 还能被 2 整除,结果是 30 ,30 还能被 2 整除,结果是 15,15不能被 2 整除,但 15 能被 3 正常,结果是 5 ,5 不能被 3 整除,但 5 能被 5 整除,结果是 1 ,退出循环。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
int n;
printf("请输入整数:");
scanf("%d", &n);// 输入需要分解的整数
printf("%d=", n);
// 遍历2到n之间的整数是否是n的质因数,注意这里个n是变动的
for (int i = 2; i <= n; i++) {
while (n % i == 0) {
printf("%d", i);// 打印质因数
n /= i;// 改变n的值。
if (n != 1)
printf("*");
}
}
return 0;
}
运行结果:
请输入整数:120
120=2*2*2*3*5
015,(a>b)?a:b
题目:利用条件运算符的嵌套来完成此题:学习成绩>=90分的同学用A表示,60-89分之间的用B表示,60分以下的用C表示。
问题分析:在三目运算符中 c ? a : b ,如果 c 为true,则返回 a ,否则返回 b 。这里我们可以使用三目运算符嵌套来完成此题。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
int s;// 学生成绩
printf("请输入分数: ");
scanf("%d", &s);// 输入成绩
char g = (char) (s >= 90 ? 'A' : (s >= 60 ? 'B' : 'C'));
printf("%c", g);
return 0;
}
运行结果:
请输入分数:96
A
016,最大公约数和最小公倍数
题目:输入两个正整数 a 和 b ,求其最大公约数和最小公倍数。
问题分析:最大公约数可以使用辗转相除法和更相减损术两种方式求,这里我们使用辗转相除法来计算最大公约数。最小公倍数可以用输入的两个数之积除于它们的最大公约数求。比如计算 33 和 12 的最大公约数,(33,12)→(12,9)→(9,3),因为 9 能被 3 整除,所以33和12的最大公约数是 3 。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h>
// 辗转相除法求最大公约数
int gcd(int a, int b) {
if (a < b)// 要保证 a 比 b 大
return gcd(b, a);
if (a % b == 0)// 如果 a 能被 b 整除,直接返回 b 的值。
return b;
return gcd(b, a % b);// 递归
}
int main() {
int a, b;
printf("请输入两个数字:\n");
scanf("%d %d", &a, &b);// 不能有 0 。
int t = gcd(a, b);// 计算最大公约数
int y = a * b / t;// 根据最大公约数计算最小公倍数
printf("这两个数的最大公约数是%d,最小公倍数是%d\n", t, y);
return 0;
}
运行结果:
请输入两个数字:
12 28
这两个数的最大公约数是4,最小公倍数是84
017,统计字母、数字等
题目:输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
问题分析:对于输入字符进行统计,直到遇到换行符为止。
/**
* Created by 公众号:数据结构和算法
* Copyright ? wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
char c;// 输入的字符
int l = 0, s = 0, d = 0, t = 0;
printf("请输入一些字符:\n");
while ((c = getchar()) != '\n') {// 直到遇到换行符为止
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
l++;// 英文字母
} else if (c >= '0' && c <= '9') {
d++;// 数字
} else if (c == ' ') {
s++;// 空格
} else {
t++;// 其他字符
}
}
printf("字母=%d, 数字=%d, 空格 =%d, 其他=%d", l, d, s, t);
return 0;
}
运行结果:
请输入一些字符:
wansuanfa.com 666&*()
字母 = 12, 数字 = 3, 空格 = 1, 其他 = 5
018,s=a+aa+aaa...
题目:求s=a+aa+aaa+aaaa+aa...a的值,其中a是一个数字。例如2+22+222+2222+22222(此时共有5个数相加),几个数相加有键盘控制。
问题分析:输入的 n 是数字的个数,把所有数字相加即可。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
int s = 0, a, n, t;
printf("请输入 a 和 n:\n");
scanf("%d %d", &a, &n);
t = a;
while (n > 0) {
s += t;
a = a * 10;
t += a;
n--;
}
printf("a+aa+...=%d\n", s);
return 0;
}
运行结果:
a 和 n:
2 5
24690 =
019,完数
题目:一个数如果恰好等于它的因子之和,这个数就称为"完数",例如 6=1+2+3 ,请编程找出 1000 以内的所有完数。
问题分析:计算1000以内每个数的因数,判断因数之和是否等于该数,如果等于,则是完数,否则不是。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
int k, a[256];
for (int i = 1; i < 1000; i++) {
int sum = 0;// 累加因子之和
k = 0;
for (int j = 1; j <= i / 2; j++)
if (i % j == 0) {
sum += j;
a[k++] = j;// 记录因子
}
if (i == sum) {// 是否是完数
printf("%d=%d", i, a[0]);
for (int j = 1; j < k; ++j)
printf("+%d", a[j]);// 打印因子
printf("\n");// 换行
}
}
return 0;
}
运行结果:
6=1+2+3
28=1+2+4+7+14
496=1+2+4+8+16+31+62+124+248
020,小球自由下落
题目:一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在第10次落地时,共经过多少米?第10次反弹多高?
问题分析:反弹的高度是原来的一半,路径是反弹高度的两倍,因为反弹需要上和下两个方向。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
float h = 100;// 初始高度
float s = 100;// 经过的长度
for (int i = 1; i <= 10; i++) {
h = h / 2;// 每次反弹的高度是原来的一半
s += 2 * h;// 经过长度需要累加反弹高度的2倍
}
printf("第10次落地时,共经过%f米,第10次反弹高%f米\n", s, h);
return 0;
}
运行结果:
第10次落地时,共经过299.804688米,第10次反弹高0.097656米
021,猴子吃桃问题
题目:猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少。
问题分析:采取逆向思维的方法,从后往前推断。第 10 天 1 个桃子,第 9 天是2*(1+1)=4个桃子,第 8天是2*(4+1)=10个桃子,以此类推,如果当天吃了 x 个桃子,那么前一天就是2*(x+1)个桃子。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int main() {
int n = 1;
for (int i = 1; i < 10; i++)
n = (n + 1) * 2;
printf("总数为:%d", n);
return 0;
}
运行结果:
总数为:1534
022,乒乓球推理
题目:两个乒乓球队进行比赛,各出三人。甲队为a,b,c三人,乙队为x,y,z三人。已抽签决定比赛名单。有人向队员打听比赛的名单。a说他不和x比,c说他不和x,z比,请编程序找出三队赛手的名单。
问题分析:c 不和 x,z 比,所以 c 只能和 y 比,a 不和 x 比,所以 a 只能和 z 比,那么 b 只能和 x 比,直接能推算出来,但这里要写出程序,我们来看下。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int main() {
for (int a = 'y'; a <= 'z'; a++) {// a 不能和 x 比,跳过 x
for (int b = 'x'; b <= 'z'; b++) {// b
if (a == b)// a与b不能和同一个人比较
continue;
for (int c = 'y'; c <= 'y'; c++) {// c不和x,z比
if (a != c && b != c)// c与a,c不能和同一个人比较,
printf("笔试名单为:a--%c\tb--%c\tc--%c\n",
a, b, c);
}
}
}
return 0;
}
运行结果:
顺序为:a--z b--x c--y
023,打印菱形
题目:打印出如下图案(菱形)。
*
***
*****
*******
*****
***
*
问题分析:先把菱形分成两部分来看待,先打印前 4 行,在打印后 3 行。每行只打印左边的空格,右边的空格不需要打印。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int main() {
for (int i = 0; i <= 3; i++) {// 包括之间一行,总共4行
for (int j = 0; j <= 2 - i; j++)
printf(" ");// 左边的空格
for (int k = 0; k <= 2 * i; k++)
printf("*");
printf("\n");// 换行
}
for (int i = 0; i <= 2; i++) {// 下面打印3行
for (int j = 0; j <= i; j++)
printf(" ");// 左边的空格
for (int k = 0; k <= 4 - 2 * i; k++)
printf("*");
printf("\n");
}
return 0;
}
运行结果:
*
***
*****
*******
*****
***
*
024,2/1+3/2+5/3...
题目:有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13...求出这个数列的前20项之和。
问题分析:如果把分子和分母单独拿出来,它们都是斐波那契数列,可以参考 011,兔子生崽,直接累加分数即可。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
float sum = 0;// 记录分数之和
float t, a = 2, b = 1;// a 是分子,b是分母
for (int i = 1; i <= 20; i++) {
sum += a / b;// 累加分数
// 更新 a ,b 的值
t = a + b;
b = a;
a = t;
}
printf("%9.6f\n", sum);
return 0;
}
运行结果:
32.660263
025,求阶乘的和
题目:求 1 + 2! + 3! + ... + 20! 的和。
问题分析:计算阶乘的值然后累加即可。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
long double sum = 0, m = 1;
for (int i = 1; i <= 20; i++) {
m *= i;// 计算阶乘
sum += m;// 累加阶乘值
}
printf("%Lf\n", sum);
return 0;
}
运行结果:
2561327494111820313.000000
026,递归求阶乘
题目:利用递归方法求5!。
问题分析:递归公式fun(n)=fun(n-1)*n,当 n 等于 1 的时候,直接返回 1 即可。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int fun(int n) {
if (n == 1)
return 1;
return fun(n - 1) * n;// 递归
}
int main() {
for (int i = 1; i <= 5; i++)
printf("%d!=%d\n", i, fun(i));
return 0;
}
运行结果:
1!=1
2!=2
3!=6
4!=24
5!=120
027,逆序打印字符
题目:利用递归函数调用方式,将所输入的5个字符,以相反顺序打印出来。
问题分析:当输入的字符个数不够 5 个的时候,一直递归输入,当输入 5 个字符的时候开始输出。递归类似于栈,先压栈,后出栈,所以出栈的顺序和输入的顺序是相反的。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
void print(int n) {
char ch = getchar();// 输入字符
if (n <= 1) {// n 等于 1 的时候开始输出
printf("相反顺序输出结果:");
} else {
print(n - 1);// 递归
}
putchar(ch);// 输出字符。
}
int main() {
int i = 5;
printf("请输入%d个字符:", i);
print(i);
return 0;
}
运行结果:
请输入5个字符:qwert
相反顺序输出结果:trewq
028,岁数推理
题目:有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。请问第五个人多大?
问题分析:使用递归的方式,第一个人是 10 岁,第 n 个人的年龄是第 n-1 个人的年龄加 2 。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int age(int n) {
if (n == 1)// 第一个人是 10 岁
return 10;
return age(n - 1) + 2;// 递归
}
int main() {
printf("第五个人的岁数是:%d\n", age(5));
return 0;
}
运行结果:
第五个人的岁数是:18
029,逆序打印各位数字
题目:给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。
问题分析:最多5位数,可以获取数字的每一位,如果万位不等于 0 ,肯定是 5 位数,如果万位是 0 ,千位不等于 0 ,则是 4 位数……,根据这样判断,然后逆序输出。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int main() {
int x;
printf("请输入 5 位数字:");
scanf("%d", &x);
int a = x / 10000; // 万位数
int b = x % 10000 / 1000; // 千位数
int c = x % 1000 / 100; // 百位数
int d = x % 100 / 10; // 十位数
int e = x % 10; // 个位数
if (a != 0) {
printf("是5位数,逆序为:%d %d %d %d %d", e, d, c, b, a);
} else if (b != 0) {
printf("是4位数,逆序为:%d %d %d %d", e, d, c, b);
} else if (c != 0) {
printf("是3位数,逆序为:%d %d %d", e, d, c);
} else if (d != 0) {
printf("是2位数,逆序为:%d %d", e, d);
} else if (e != 0) {
printf("是1位数,逆序为:%d", e);
}
return 0;
}/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int main() {
int x;
printf("请输入 5 位数字:");
scanf("%d", &x);
int a = x / 10000; // 万位数
int b = x % 10000 / 1000; // 千位数
int c = x % 1000 / 100; // 百位数
int d = x % 100 / 10; // 十位数
int e = x % 10; // 个位数
if (a != 0) {
printf("是5位数,逆序为:%d %d %d %d %d", e, d, c, b, a);
} else if (b != 0) {
printf("是4位数,逆序为:%d %d %d %d", e, d, c, b);
} else if (c != 0) {
printf("是3位数,逆序为:%d %d %d", e, d, c);
} else if (d != 0) {
printf("是2位数,逆序为:%d %d", e, d);
} else if (e != 0) {
printf("是1位数,逆序为:%d", e);
}
return 0;
}
运行结果:
请输入 5 位数字:12345
是5位数,逆序为:5 4 3 2 1
030,判断是否回文数
题目:一个5位数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同。
问题分析:一个5位数,只需要提取它的个位,十位,千万,万位数字即可,如果个位和万位数字相等,并且十位和千位数字相等,则是回文数,否则不是。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
int main() {
int x;
printf("请输入 5 位数字:");
scanf("%d", &x);
int wan = x / 10000; // 万位数
int qian = x % 10000 / 1000; // 千位数
int shi = x % 100 / 10; // 十位数
int ge = x % 10; // 个位数
if (ge == wan && shi == qian) {
printf("这是回文数");
} else {
printf("这不是回文数");
}
return 0;
}
运行结果:
请输入 5 位数字:12321
这是回文数
031,判断星期几
题目:请输入星期几的第一个字母来判断一下是星期几,如果第一个字母一样,则继续判断第二个字母。
问题分析:使用Switch语句,如果第一个字母一样,则输入第二个怎么继续判断。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
char i, j;
printf("请输入第一个字母:");
scanf("%c", &i);// 输入字符
getchar();// 获取换行符。
switch (i) {
case 'm':
printf("monday");// 周一
break;
case 'w':
printf("wednesday");// 周三
break;
case 'f':
printf("friday");// 周五
break;
case 't':
printf("请输入下一个字母:");
scanf("%c", &j);
if (j == 'u') {// 周二
printf("tuesday");
break;
}
if (j == 'h') {// 周四
printf("thursday");
break;
}
case 's':
printf("请输入下一个字母");
scanf("%c", &j);
if (j == 'a') {// 周六
printf("saturday");
break;
}
if (j == 'u') {// 周日
printf("sunday");
break;
}
default :
printf("error");
break;
}
return 0;
}
运行结果:
请输入第一个字母:t
请输入下一个字母:u
tuesday
032,删字符串中的指定字母
题目:删除一个字符串中的指定字母,如:字符串 "aca",删除其中的 a 字母。
问题分析:逐个判断原字符串中的字符是否是需要删除的,如果不是删除的则保留。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
#include <string.h>
// 删除字符串中指定字母
char *deleteCharacters(char *str, char *del) {
// 如果要删除的字符集为空,则直接返回原字符串
if (del == NULL)
return str;
// 用于存储要删除的字符的哈希表
int hash[256] = {0};
// 标记哪些字符需要删除
for (int i = 0; i < strlen(del); i++)
hash[del[i]] = 1;
int curIndex = 0;
// 通过遍历字符串来删除指定的字符
for (int i = 0; i < strlen(str); i++) {
// 如果当前字符不在要删除的字符集中,则保留该字符
if (!hash[str[i]])
str[curIndex++] = str[i];
}
str[curIndex] = '\0'; // 字符串结束的标志
return str;
}
int main() {
char s1[] = "acasftd"; // 原字符串
char s2[] = "as"; // 要删除的字母
// 打印删除指定字符后的字符串
printf("删除之后的字符串是:%s", deleteCharacters(s1, s2));
return 0;
}
运行结果:
删除之后的字符串是:cftd
033,判断是否质数
题目:判断一个数字是否为质数。
问题分析:质数(prime number)又称素数。一个大于1的自然数,除了 1 和它本身外,不能被其他自然数整除。如果一个数不是素数,则肯定有一个因数 x,且 2<=x<=sqrt(x) 。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#include <stdbool.h>
#include<math.h>
bool isPrime(int n) {// 判断 n 是否是素数
if (n < 2)// 最小的素数是 2 。
return false;
int sq = (int) sqrt(n);// 先计算n的平方根
for (int i = 2; i <= sq; i++) {
if (n % i == 0)
return false;// 不是素数
}
return true;// 是素数
}
int main() {
int n = 0;
printf("请输入一个自然数:");
scanf("%d", &n);
int ans = isPrime(n);
if (ans) {
printf("是素数");
} else
printf("不是素数");
return 0;
}
运行结果:
请输入一个自然数:18
不是素数
034,练习函数调用
题目:练习函数调用。
问题分析:略
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
void say(void) {
printf("公众号:数据结构和算法,\n");
printf("一个专门讲算法的公众号!\n");
}
void three_say(void) {
for (int counter = 1; counter <= 3; counter++)
say();// 调用上面函数3次
}
int main() {
three_say();// 函数调用
return 0;
}
运行结果:
公众号:数据结构和算法,
一个专门讲算法的公众号!
公众号:数据结构和算法,
一个专门讲算法的公众号!
公众号:数据结构和算法,
一个专门讲算法的公众号!
035,字符串反转
题目:字符串反转,如将字符串 "www.wansuanfa.com" 反转为 "moc.afnausnaw.www"。
问题分析:使用两个指针left和right,刚开始的时候分别指向字符串的两端,然后交换这两个指针指向的字符,交换完之后两个指针分别往中间移,继续交换,直到两个指针相遇或者left>right为止。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
#include <string.h>
void reverse(char *s) {// 反转字符串
// 获取字符串长度
int len = strlen(s);
// 使用双指针
int left = 0, right = len - 1;
while (left < right) {
// 交换两个指针指向的字符
char ch = *(s + left);
*(s + left) = *(s + right);
*(s + right) = ch;
// 两个指针往中间移
left++;
right--;
}
}
int main() {
char s[] = "www.wansuanfa.com";
printf("原字符串是:'%s'\n", s);
reverse(s); // 反转字符串
printf("反转之后的字符串是:'%s'\n", s);
return 0;
}
运行结果:
原字符串是:'www.wansuanfa.com'
反转之后的字符串是:'moc.afnausnaw.www'
036,100内的素数
题目:求100之内的素数。
问题分析:计算素数的方式比较多,可以直接筛选,也可以使用埃氏筛选法,还可以使用欧拉筛,详细内容可以关注公众号"数据结构和算法"进行获取。我们这里使用埃氏筛选法的方式来计算100以内的素数,对于一个素数,它的倍数(大于等于2)肯定不是素数,我们把素数的倍数都标记一下,代码如下。
/**
* Created by 公众号:数据结构和算法
* Copyright © wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#include <stdbool.h>
#include <memory.h>
int main() {
// 埃氏筛选法求素数
const int N = 100;
int prime[N + 1];// 记录素数
int count = 0;// 素数的个数
bool vis[N + 1];// 记录数字,false表示素数,true表示不是素数。
memset(vis, 0, sizeof vis);// 默认都是素数
for (int i = 2; i <= N; ++i) {
if (!vis[i]) {// 如果是素数
prime[count++] = i;// 记录素数
// 素数的倍数不是素数。
for (int j = 2 * i; j <= N; j += i)
vis[j] = true;
}
}
// 打印100以内的素数
for (int i = 0; i < count; ++i) {
printf("%d ", prime[i]);
if ((i + 1) % 5 == 0)// 5个一换行
printf("\n");
}
return 0;
}
运行结果:
2 3 5 7 11
13 17 19 23 29
31 37 41 43 47
53 59 61 67 71
73 79 83 89 97
037,排序
题目:对10个数进行排序。
问题分析:关于排序算法比较多,我之前写过《20多种排序算法》,我们可以从中随便选择一个,这里我们使用冒泡排序来解。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#define N 10
// 交换数组中两个元素的值。
void swap(int arr[], int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
// 冒泡排序。
void sort(int arr[], int n) {
for (int i = 1; i < n; i++) {// 只需要比较 n-1 轮即可。
for (int j = 0; j < n - i; j++) {
// 如果当前元素大于它的下一个元素,则交换他俩的值。
if (arr[j] > arr[j + 1])
swap(arr, j, j + 1);
}
}
}
int main() {
int arr[N];
printf("请输入 %d 个数字:\n", N);
for (int i = 0; i < N; i++)
scanf("%d", &arr[i]);// 输入10个数字
sort(arr, N);// 排序
printf("排序结果是:\n");
for (int i = 0; i < N; i++)
printf("%d ", arr[i]);// 打印排序结果
return 0;
}
运行结果:
10 个数字:
2 3 6 7 8 56 34 8 12 13
:
2 3 6 7 8 8 12 13 34 56
038,矩阵对角元素和
题目:求一个3*3矩阵对角线元素之和
问题分析: 输入二维矩阵,累加a[i][i]即可。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#define N 3
int main() {
int a[N][N], sum = 0;
printf("请输入矩阵(3*3):\n");
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
scanf("%d", &a[i][j]);
for (int i = 0; i < N; i++)
sum += a[i][i];
printf("对角线之和为:%d\n", sum);
return 0;
}
运行结果:
请输入矩阵(3*3):
1 2 3
4 5 6
7 8 9
对角线之和为:15
039,一个数插入数组
题目:有一个已经排好序的数组。现输入一个数 x ,要求按原来的规律将它插入数组中。
问题分析:从后往前把大于 x 的值全部往后挪,找到插入的位置之后,再把数字插入对应的位置。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
int a[11] = {3, 4, 6, 9, 26, 37, 42, 58, 60, 82};
int num;// 需要插入的数字
printf("原始数组是:\n");
for (int i = 0; i < 10; i++)// 打印原始数组
printf("%-4d", a[i]);
printf("\n插入一个新的数字: ");
scanf("%d", &num);// 输入要插入的数字
int i = 9;
while (i >= 0) {// 查找插入位置
if (a[i] > num) {
a[i + 1] = a[i];// 往后挪
} else {
break;// 找到插入的位置,停止查找
}
i--;
}
a[i + 1] = num;// 插入需要插入的位置
for (i = 0; i < 11; i++)// 打印插入之后的数组
printf("%-4d", a[i]);
return 0;
}
运行结果:
原始数组是:
3 4 6 9 26 37 42 58 60 82
插入一个新的数字:16
3 4 6 9 16 26 37 42 58 60 82
040,数组逆序输出
题目:将一个数组逆序输出。
问题分析:从后往前输出即可。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#define N 10
int main() {
int a[N] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
printf("原始数组是:\n");
for (int i = 0; i < N; i++)
printf("%d ", a[i]);
printf("\n逆序之后的数组:\n");
for (int i = N - 1; i >= 0; i--)
printf("%d ", a[i]);
return 0;
}
运行结果:
原始数组是:
0 1 2 3 4 5 6 7 8 9
逆序之后的数组:
9 8 7 6 5 4 3 2 1 0
041,static用法1
题目:学习 static 定义静态变量的用法。
在 C 语言中,static 关键字用于声明静态变量,和静态函数。静态变量在声明时被初始化,只被初始化一次,而且在整个程序的生命周期内都保持存在。在函数内声明的静态变量只能在该函数内访问,而在函数外声明的静态变量则只能在该文件内访问。而静态函数可以参考 043,static用法2。
问题分析:以下函数中 fun() 声明了一个静态变量 x,并将其初始化为 0。每次调用 fun() 函数时,x 的值都会加 1,并打印出新的值。由于 x 是静态变量,它在程序的整个生命周期中都存在。因此,每次调用 fun() 时,它都可以记住 x 的值,并在此基础上递增。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
void fun() {
static int x = 0;// 定义静态变量
x++;// 加 1 。
printf("%d\n", x);
}
int main() {
fun(); // 输出 1
fun(); // 输出 2
fun(); // 输出 3
return 0;
}
运行结果:
1
2
3
042,auto用法
题目:学习使用auto定义变量的用法。
问题分析:在C语言中,auto 关键字用于声明变量时指定变量的存储类别。auto 关键字告诉编译器该变量的生命周期仅限于定义它的代码块(通常是函数)之内,即该变量是自动存储的。这意味着变量的存储是在栈上分配的,而不是在静态存储区域(如全局变量或静态局部变量)。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <stdio.h>
void fun() {
auto int x = 10; // x 是自动存储的局部变量
x++;
printf("x 变量为 %d \n", x);
}
int main() {
fun();
fun();
fun();
return 0;
}
运行结果:
x 变量为 11
x 变量为 11
x 变量为 11
043,static用法2
题目:学习使用static的另一用法。
问题分析:static声明的函数和变量只能在该文件中使用,这和面向对象语言中的private关键字声明的函数和变量类似。比如在file1.c文件中定义了一个static函数,在file2.c文件中调用这个函数就会出现错误。如果把file1.c文件中的static关键字去掉,在file2.c文件中就可以调用这个函数了。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
// file1.c
#include <stdio.h>
static void printStatic() {
printf("static void");
}
// file2.c
#include<stdio.h>
extern void printStatic();// 不能调用
int main() {
printStatic();
return 0;
}
044,extern的使用
题目:学习使用如何调用外部函数。
问题分析:比如在file1.c文件中定义了一个变量name和一个函数printVal,但在file2.c文件中调用这个变量和函数,需要添加extern关键字。如果不要extern关键字,可以参考 050,#include练习 。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
// file1.c
#include<stdio.h>
int name = 10;
void printVal(int val) {
printf("printVal is:%d", val);
}
// file2.c
#include<stdio.h>
extern int name;// 引用外部变量
extern void printVal(int val);// 引用外部函数
int main() {
printVal(name + 10);
return 0;
}
运行结果:
printVal is:20
045,register用法
题目:学习使用register定义变量的方法。
问题分析:在 C 语言中,register 关键字用于向编译器建议将某个变量存储在寄存器中,以提高对该变量的访问速度。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
int main() {
int sum = 0;
for (register int i = 1; i <= 100; i++)
sum += i;
printf("1到100所有数字的和为:%d", sum);
return 0;
}
运行结果:
1到100所有数字的和为:5050
046,宏#define练习1
题目:宏#define命令练习。
问题分析:宏的功能比较强大,主要有:1,定义常量,2. 创建类型别名,3. 定义简单的函数替代,4. 定义复杂的代码片段,5. 条件编译,6. 宏参数的字符串化,7. 宏参数的连接。
我们先来看前两个,定义常量和创建类型别名。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#define PI 3.14159 // 定义PI的值为3.14159
#define INT32 int // 定义INT32表示int类型
int main() {
// 下面定义了两个int类型的变量
INT32 a = 1314;
INT32 r = 520;
// 计算圆的面积
double s = PI * r * r;
printf("变量 a 的值是:%d \n", a);
printf("圆的半径 r 是:%d \n", r);
printf("圆的面积 s 是:%lf \n", s);
return 0;
}
运行结果:
变量 a 的值是:1314
圆的半径 r 是:520
圆的面积 s 是:849485.936000
047,宏#define练习2
题目:宏#define命令练习2。
问题分析:下面再来看下使用宏定义简单的函数替代和定义复杂的代码片段。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#define SQUARE(x) ((x) * (x))
#define exchange(a, b) { int t;t=a;a=b;b=t;}// 放在一行里
int main() {
int a = 10;
int b = 20;
int sq = SQUARE(a);
printf("交换之前 a=%d; b=%d\n", a, b);
printf("交换之前 a 的平方是:%d\n", sq);
exchange(a, b);
printf("交换之后 a=%d; b=%d\n", a, b);
return 0;
}
运行结果:
交换之前 a=10; b=20
交换之前 a 的平方是:100
交换之后 a=20; b=10
048,宏#define练习3
题目:宏#define命令练习3。
问题分析:除此之外,宏还有其他一些定义和操作。比如 #define 可以使用 # 操作符将宏参数转换为字符串,#define 可以使用 ## 操作符将两个宏参数连接成一个标识符。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#define STR(x) #x // 将参数x转换为字符串
#define CONCAT(x, y) x##y // 将两个宏参数连接成一个标识符
int main() {
int CONCAT(my, age) = 18;
printf("将参数a转换为字符串:%s\n", STR(name));
printf("将两个宏参数连接成一个标识符:%d", myage);
return 0;
}
运行结果:
将参数a转换为字符串:name
将两个宏参数连接成一个标识符:18
049,#if,#ifdef,#ifndef
题目:#if #ifdef和#ifndef的综合应用。
问题分析:常见的条件编译指令
#ifdef:如果宏已定义,则编译以下代码。
#ifndef:如果宏未定义,则编译以下代码。
#if:根据条件表达式的值编译代码。
#else:如果前面的条件不满足,则编译以下代码。
#elif:在 #if 或 #else 后,提供另一个条件。
#endif:结束条件编译块。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#define NAME // 定义名字name
int main() {
#ifdef NAME
printf("NAME 被定义了。。。\n");
#else
printf("NAME 没有被定义。。。\n");
#endif
#ifndef AGE
printf("AGE 没有被定义。。。\n");
#else
printf("AGE 被定义了。。。\n");
#endif
#undef NAME
#ifdef NAME
printf("NAME 取消定义失败。。。\n");
#else
printf("NAME 取消定义成功。。。\n");
#endif
#define AGE
#ifndef AGE
printf("AGE 定义失败。。。\n");
#else
printf("AGE 定义成功。。。\n");
#endif
return 0;
}
运行结果:
NAME 被定义了。。。
AGE 没有被定义。。。
NAME 取消定义成功。。。
AGE 定义成功。。。
050,#include练习
题目:#include 的应用练习。
问题分析:在C语言中,#include 预处理指令用于包含头文件,这是C语言程序中非常常见的操作。头文件通常包含函数声明、宏定义、类型定义、模板声明等,它们可以被多个源文件共享。
#include 指令通常有两种格式:
1,尖括号 < >:用于标准库头文件。编译器会在预定义的目录中搜索这些头文件。
2,双引号 " ":用于用户自定义的头文件或第三方库头文件。编译器首先在包含当前文件的同一目录中搜索,如果找不到,再在标准库目录中搜索。
假如我们创建两个文件,一个是头文件 test.h ,还一个是主文件,头文件test.h中的代码如下,可以看到和 044,extern的使用 的区别就是这里不需要再使用extern关键字导入了。
// 在头文件中定义的常量
#define NAME "公众号:数据结构和算法
主文件中的代码如下:
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
#include "test.h"// 引用头文件
int main() {
// 打印头文件中定义的常量
printf("%s\n", NAME);
return 0;
}
运行结果:
公众号:数据结构和算法
051,按位与 &
题目:学习使用按位与 &。
问题分析:按位与有 4 种情况,只要有一个是 0 ,结果就是 0 。
0 & 0=0;
0 & 1=0;
1 & 0=0;
1 & 1=1;
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
void printBinary(int num) {// 打印二进制
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
printf("%d", bit);
if (i % 8 == 0)// 每8个加一个空格
printf(" ");
}
printf("\n");
}
int main() {
int a = 23, b = 13;
printf("整数 a 的值是:%d,二进制表示如下:\n", a);
printBinary(a);
printf("整数 b 的值是:%d,二进制表示如下:\n", b);
printBinary(b);
int and = a & b;
printf("a 和 b 按位 & 的值是:%d,二进制表示如下:\n", and);
printBinary(and);
return 0;
}
运行结果:
a 的值是:23,二进制表示如下:
00000000 00000000 00000000 00010111
b 的值是:13,二进制表示如下:
00000000 00000000 00000000 00001101
a 和 b 按位 & 的值是:5,二进制表示如下:
00000000 00000000 00000000 00000101
052,按位或 |
题目:学习使用按位或 |。
问题分析:按位或有 4 种情况,只要有一个是 1 ,结果就是 1 。
0 | 0=0;
0 | 1=1;
1 | 0=1;
1 | 1=1;
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
void printBinary(int num) {// 打印二进制
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
printf("%d", bit);
if (i % 8 == 0)// 每8个加一个空格
printf(" ");
}
printf("\n");
}
int main() {
int a = 18, b = 13;
printf("整数 a 的值是:%d,二进制表示如下:\n", a);
printBinary(a);
printf("整数 b 的值是:%d,二进制表示如下:\n", b);
printBinary(b);
int or = a | b;
printf("a 和 b 按位 | 的值是:%d,二进制表示如下:\n", or);
printBinary(or);
return 0;
}
运行结果:
a 的值是:18,二进制表示如下:
00000000 00000000 00000000 00010010
b 的值是:13,二进制表示如下:
00000000 00000000 00000000 00001101
a 和 b 按位 | 的值是:31,二进制表示如下:
00000000 00000000 00000000 00011111
053,按位异或 ^
题目:学习使用按位异或 ^。
问题分析:按位异或有 4 种情况,相同的为 0 ,不同的为 1 。
0 ^ 0=0;
0 ^ 1=1;
1 ^ 0=1;
1 ^ 1=0;
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
void printBinary(int num) {// 打印二进制
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
printf("%d", bit);
if (i % 8 == 0)// 每8个加一个空格
printf(" ");
}
printf("\n");
}
int main() {
int a = 17, b = 13;
printf("整数 a 的值是:%d,二进制表示如下:\n", a);
printBinary(a);
printf("整数 b 的值是:%d,二进制表示如下:\n", b);
printBinary(b);
int xor = a ^ b;
printf("a 和 b 按位 ^ 的值是:%d,二进制表示如下:\n", xor);
printBinary(xor);
return 0;
}
运行结果:
a 的值是:17,二进制表示如下:
00000000 00000000 00000000 00010001
b 的值是:13,二进制表示如下:
00000000 00000000 00000000 00001101
a 和 b 按位 ^ 的值是:28,二进制表示如下:
00000000 00000000 00000000 00011100
054,取数右端4~7位
题目:取一个整数 a 从右端开始的 4~7 位。
问题分析:假设最右边的是第 1 位,步骤如下:
1,先使 a 右移 3 位(右边的3为舍弃,后面从第4位开始截取)
2,设置一个低 4 位全为 1,其余全为 0 的数,因为 -1 的二进制全是 1 ,可以让它左移 4位,然后取反。
3,将上面二者进行 & 运算即可。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
void printBinary(int num) {// 打印二进制
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
printf("%d", bit);
if (i % 8 == 0)// 每8个加一个空格
printf(" ");
}
printf("\n");
}
int main() {
int a, b, c;
printf("请输入整数:\n");
scanf("%d", &a);
printf("数字 a 的二进制是:\n");
printBinary(a);
a >>= 3;// 往右移3位
// -1 的二进制都是 1 ,即……1111111,左移4位变成……1110000
b = (-1) << (7 - 4 + 1);
b = ~b;// 取反变成……0001111,前面都是 0 。
c = a & b;// 截取 a 的四位。
printf("数字 a 右边的4到7位是:\n", c);
printBinary(c);
return 0;
}
运行结果:
请输入整数:
206
a 的二进制是:
00000000 00000000 00000000 11001110
a 右边的4到7位是:
00000000 00000000 00000000 00001001
055,按位取反~
题目:学习使用按位取反~。
问题分析:二进制中 0 变成 1 ,1 变成 0 。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include<stdio.h>
void printBinary(int num) {// 打印二进制
for (int i = 31; i >= 0; i--) {
int bit = (num >> i) & 1;
printf("%d", bit);
if (i % 8 == 0)// 每8个加一个空格
printf(" ");
}
printf("\n");
}
int main() {
int a = 203;
printf("a 的二进制表示如下:\n");
printBinary(a);
a = ~a;
printf("a 按位取反之后的二进制表示如下:\n");
printBinary(a);
return 0;
}
运行结果:
a 的二进制表示如下:
00000000 00000000 00000000 11001011
a 按位取反之后的二进制表示如下:
11111111 11111111 11111111 00110100
056,画圆形
题目:画圆形。
问题分析:这里是通过windows.h头文件来绘制圆,圆的绘制在WindowProc函数中。
/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <windows.h>
// 窗口过程函数,处理窗口的消息
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam) {
HDC hdc; // 设备上下文句柄,用于绘制
PAINTSTRUCT ps; // 绘制结构,包含绘制所需的信息
RECT rect; // 矩形区域,用于定义圆的位置和大小
switch (uMsg) {
case WM_PAINT: // 窗口需要重绘时发送的消息
hdc = BeginPaint(hwnd, &ps); // 准备绘制
// 矩形的左上角(100, 100),右下角(300, 300)
SetRect(&rect, 100, 100, 300, 300);
// 使用Ellipse函数绘制圆
Ellipse(hdc, rect.left, rect.top,
rect.right, rect.bottom);
EndPaint(hwnd, &ps); // 结束绘制
break;
case WM_DESTROY: // 窗口被销毁时发送的消息
PostQuitMessage(0); // 发送退出消息,结束应用程序
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
// WinMain函数,Windows应用程序的入口点
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
WNDCLASS wc = {0}; // 窗口类结构体,用于注册窗口类
// 设置窗口类参数
wc.lpfnWndProc = WindowProc; // 窗口过程函数
wc.hInstance = hInstance; // 当前实例句柄
wc.lpszClassName = "MyWindowClass"; // 窗口类名
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); // 背景画刷
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 光标
wc.style = CS_HREDRAW | CS_VREDRAW; // 窗口风格
// 注册窗口类
RegisterClass(&wc);
// 创建窗口
HWND hwnd = CreateWindowEx(
0, // 扩展风格
"MyWindowClass", // 窗口类名
"该圆由 \"公众号:数据结构和算法\" 绘制", // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口风格
CW_USEDEFAULT, CW_USEDEFAULT, 500, 400, // 位置和大小
NULL, // 父窗口
NULL, // 菜单
hInstance, // 实例句柄
NULL // 附加数据
);
ShowWindow(hwnd, nCmdShow); // 显示窗口
UpdateWindow(hwnd); // 更新窗口
MSG msg; // 消息结构体,用于接收消息
// 消息循环
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg); // 翻译消息
DispatchMessage(&msg); // 分发消息
}
return (int) msg.wParam; // 返回消息参数
}/**
* Created by 公众号:数据结构和算法
* Copyright wansuanfa.com All rights reserved.
*/
#include <windows.h>
// 窗口过程函数,处理窗口的消息
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam) {
HDC hdc; // 设备上下文句柄,用于绘制
PAINTSTRUCT ps; // 绘制结构,包含绘制所需的信息
RECT rect; // 矩形区域,用于定义圆的位置和大小
switch (uMsg) {
case WM_PAINT: // 窗口需要重绘时发送的消息
hdc = BeginPaint(hwnd, &ps); // 准备绘制
// 矩形的左上角(100, 100),右下角(300, 300)
SetRect(&rect, 100, 100, 300, 300);
// 使用Ellipse函数绘制圆
Ellipse(hdc, rect.left, rect.top,
rect.right, rect.bottom);
EndPaint(hwnd, &ps); // 结束绘制
break;
case WM_DESTROY: // 窗口被销毁时发送的消息
PostQuitMessage(0); // 发送退出消息,结束应用程序
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
// WinMain函数,Windows应用程序的入口点
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
WNDCLASS wc = {0}; // 窗口类结构体,用于注册窗口类
// 设置窗口类参数
wc.lpfnWndProc = WindowProc; // 窗口过程函数
wc.hInstance = hInstance; // 当前实例句柄
wc.lpszClassName = "MyWindowClass"; // 窗口类名
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); // 背景画刷
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 光标
wc.style = CS_HREDRAW | CS_VREDRAW; // 窗口风格
// 注册窗口类
RegisterClass(&wc);
// 创建窗口
HWND hwnd = CreateWindowEx(
0, // 扩展风格
"MyWindowClass", // 窗口类名
"该圆由 \"公众号:数据结构和算法\" 绘制", // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口风格
CW_USEDEFAULT, CW_USEDEFAULT, 500, 400, // 位置和大小
NULL, // 父窗口
NULL, // 菜单
hInstance, // 实例句柄
NULL // 附加数据
);
ShowWindow(hwnd, nCmdShow); // 显示窗口
UpdateWindow(hwnd); // 更新窗口
MSG msg; // 消息结构体,用于接收消息
// 消息循环
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg); // 翻译消息
DispatchMessage(&msg); // 分发消息
}
return (int) msg.wParam; // 返回消息参数
}
运行结果:
剩余部分可以在百度网盘下载:
链接: https://pan.baidu.com/s/1FXhdXvC7VkwWA9fQtOpHFA?pwd=6666
提取码: 6666
数组,稀疏表(Sparse Table),单向链表,双向链表,块状链表,跳表,队列和循环队列,双端队列,单调队列,栈,单调栈,双端栈,散列表,堆,字典树(Trie树),ArrayMap,SparseArray,二叉树,二叉搜索树(BST),笛卡尔树,AVL树,树堆(Treap),FHQ-Treap,哈夫曼树,滚动数组,差分数组,LRU缓存,LFU缓存
……
图的介绍,图的表示方式,邻接矩阵转换,广度优先搜索(BFS),深度优先搜索(DFS),A*搜索算法,迭代深化深度优先搜索(IDDFS),IDA*算法,双向广度优先搜索,迪杰斯特拉算法(Dijkstra),贝尔曼-福特算法(Bellman-Ford),SPFA算法,弗洛伊德算法(Floyd),卡恩(Kahn)算法,基于DFS的拓扑排序,约翰逊算法(Johnson)
……