1、拆分整数并排序
题目:编写程序,提示用户输入一个不定长的整数,将整数拆分并按从小到大顺序输出。
解决此题的两个核心操作:
- 将一个整数对10取余可得到该整数最后一位的值。可以理解为获取最后一位数。(如32857 % 10 = 7)
- 将一个整数(长度为n)对10作商可得到该整数的前n-1位整数。可以理解为减去最后一位数。(如32857 / 10 = 3275)
思路:
1. 获取整数长度:此步主要使用操作2,对整数 num 循环进行操作2,每次循环减少num的一位数并用变量 len 来记录,直到 num 被减为0,可得到长度 len。
2. 拆分整数并存储:先创建数组 nums[len] 用于存储数据,对整数 num 循环进行操作1和2,操作1用于获取最后一位数,获取后存储到数组 nums 中,然后进行操作2减去这一位数,进入下一次循环,直到 num 被减为 0,完成数据存储。
3. 对数组进行排序并输出结果:这里使用冒泡法将数组元素排序,排序完后遍历输出即可。
注:冒泡排序是非常重要的排序方法之一,原理可查看下面动图:
代码实现:
#include<stdio.h>
int length(long long); //计算整数长度
int main() {
// 提示用户输入整数
long long num;
printf("请输入一个整数:");
scanf("%lld", &num);
// 调用自定义的函数int length(long long)来计算整数长度
int len = length(num);
int nums[len];//创建数组用于存储拆散后的数
int i, j;
// 对num进行循环,每次循环获取最后一位数并存储到数组中,并减少这一位数,直到num被减为0
for (i = 0; num > 0; i++) {
nums[i] = num % 10; // 获取最后一位数
num /= 10;// 减少最后一位数
}
// 冒泡排序
for (i = len - 1; i > 0; i--) {
for (j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
// 遍历输出数组
for (i = 0; i < len; i++) {
printf("%d ", nums[i]);
}
return 0;
}
int length(long long num) {
int len = 0; // 定义len变量来记录长度
// 对num做循环,每次循环减少其一位数,直到num被减为0,循环时用len记录长度
while (num > 0) {
num /= 10; // 减少一位
len++;
}
return len;
}
2、实现开n次方函数(牛顿迭代)
题目:编写函数 double root(double num, int n) 用于返回 num 的 n 次方根,进行测试。
分析:设 x = n√num ;可得 x^n - num = 0 ;则原题可以转变为求解函数 f(x) = x^n - num 的零点。求解函数零点,在编程中一个很重要的方法是:牛顿迭代法。此题也主要是介绍和使用此方法。
牛顿迭代公式:
图片截取于:百度百科
思路:
设置任意一个初始值 x ,编写一个while循环,用牛顿迭代公式对 x 进行迭代
x1 = x0 - f(x0) / f'(x0)
x2 = x1 - f(x1) / f'(x1)
x3 = x2 - f(x2) / f'(x2)
......
xn = x(n-1) - f[x(n-1)] / f'[x(n-1)]
其中 f(x) = x^n - num
循环条件设置为 | xn - x(n-1) | > error(自定义的误差值),即当每次迭代 x 的变化量小于等于误差 error 时,循环结束。此时,得到 x 等于 error 误差范围内的 num 的 n 次方根。
每次循环,都要计算 f[x(n-1)] 与 f'[x(n-1)] (即 x^(n-1)-num 与 (n-1) * x^(n-2)) 的值,会涉及到求一个数的幂的运算,这时,我们编写一个 power 函数用于求一个数 n 次幂的值。
代码实现:
#include <stdio.h>
double root(double, int); //求一个数的n次方根
double power(double, int); //求一个数的n次方
int main() { //测试函数
double num;
int pow;
while (1) { //设置循环方便多次测试
// 提示输入num
printf("num:");
scanf("%lf", &num);
if (num == -1) break; //设置输入-1为循环出口
// 提示输入pow
printf("pow:");
scanf("%d", &pow);
if (pow == -1) break; //设置输入-1为循环出口
printf("%.2f\n", root(num, pow)); //输出结果
}
return 0;
}
//求数num的n次方根
double root(double num, int n) {
double x = num / n; //任意设置一个初始值x
double temp = num; //用于记录上一轮迭代时x的值
// 用牛顿迭代公式迭代x
// 循环条件:上一轮x与此轮x的差值大于自定义的误差值0.01
while (temp - x > 0.0001 || temp - x < -0.0001) {
temp = x; //记录上一轮x的值
//对x进行牛顿迭代
//过程中会调用power函数计算一个数的幂值
x = x - (power(x, n) - num) / (n * power(x, n - 1));
}
return x;//返回迭代结果
}
//求数num的pow次方
double power(double num, int pow) {
double temp = 1;//初始化操作为为1
//循环,让temp自乘num pow次,得到temp = num^pow
for (int i = 0; i < pow; ++i) {
temp *= num;
}
return temp;
}
小结:
两道题目都是在锻炼自己将数学思路用代码来实现的能力。
从题目一可以总结出,要对一个长整数进行分析,最实用的两个技巧就是对10的取余和作商。常用的应用场景有:身份证号码分析、学号分析等等。
题目二主要在于将数学的公式、数学的内容应用到编程上,多练习此类题目,对后续学习算法会有很大帮助。