C 语言实例 – 求一个整数的所有因数(深入浅出)

C 语言实例 – 求一个整数的所有因数

在学习 C 语言的过程中,我们常常会遇到一些基础但非常实用的编程题目。其中,“求一个整数的所有因数”就是一道典型的入门级算法题。它不仅能帮助你巩固循环、条件判断、变量定义等基础语法,还能让你理解算法效率的优化思路。

这道题看似简单,实则蕴含了多个关键知识点:如何遍历数字范围、如何判断整除关系、如何存储结果、如何避免重复计算。更重要的是,它能为你今后学习更复杂的数论算法打下坚实的基础。

今天,我们就通过一个完整的 C 语言实例,一步一步带你实现“求一个整数的所有因数”的功能。无论你是刚接触编程的初学者,还是已经有一定经验的中级开发者,都能从中获得启发。


什么是因数?从生活中的例子说起

在数学中,如果一个整数 a 能被另一个整数 b 整除(即 a 除以 b 的余数为 0),那么我们说 b 是 a 的因数。

举个生活中的例子:你有 12 块巧克力,想平均分给朋友。你可以分给 1 个人、2 个人、3 个人、4 个人、6 个人或 12 个人,每人都能分到整数块,不会剩下。所以 1、2、3、4、6、12 都是 12 的因数。

这就是“因数”的直观含义。而在编程中,我们就是要让计算机自动找出所有这样的数字。


基础思路:从 1 到 n 逐个判断

最直接的方法,就是从 1 开始,一直试到目标整数本身,看看哪个数能整除它。

我们先看一个最简单的实现方式:

#include <stdio.h>

int main() {
    int n;
    
    // 提示用户输入一个整数
    printf("请输入一个正整数:");
    scanf("%d", &n);

    // 确保输入的是正整数
    if (n <= 0) {
        printf("请输入一个大于 0 的正整数!\n");
        return 1;
    }

    // 输出标题
    printf(" %d 的所有因数为:", n);

    // 从 1 遍历到 n,判断是否能整除
    for (int i = 1; i <= n; i++) {
        if (n % i == 0) {  // 如果 n 除以 i 余数为 0,说明 i 是因数
            printf("%d ", i);  // 输出当前因数
        }
    }

    printf("\n");  // 换行
    return 0;
}

代码详解

  • #include <stdio.h>:引入标准输入输出库,用于 printfscanf
  • int n;:声明一个整型变量 n,用于存储用户输入的数。
  • scanf("%d", &n);:从键盘读取用户输入的整数,并存入 n
  • if (n <= 0):防止用户输入负数或零,因为因数通常讨论的是正整数。
  • for (int i = 1; i <= n; i++):循环从 1 到 n,尝试每个可能的因数。
  • n % i == 0:使用取模运算符 %,判断 n 是否能被 i 整除。如果余数为 0,说明 i 是因数。
  • printf("%d ", i);:输出找到的因数。
  • 最后 printf("\n"); 换行,让输出更清晰。

这个版本逻辑清晰,适合初学者理解。但它的效率并不高,尤其是当数字很大时,比如 10000,要循环 10000 次,显然浪费时间。


优化思路:只遍历到 √n

我们来思考一个关键点:因数总是成对出现的。比如 12 的因数对是:

  • 1 和 12(1 × 12 = 12)
  • 2 和 6(2 × 6 = 12)
  • 3 和 4(3 × 4 = 12)

你会发现,一旦我们找到一个小的因数(比如 3),就能立刻推出一个大的因数(4)。而且,当 i 超过 √n 时,我们已经把所有因数对都找完了。

所以,我们只需要遍历到 sqrt(n),就能找出所有因数。

以下是优化后的代码:

#include <stdio.h>
#include <math.h>  // 用于 sqrt 函数

int main() {
    int n;
    
    printf("请输入一个正整数:");
    scanf("%d", &n);

    if (n <= 0) {
        printf("请输入一个大于 0 的正整数!\n");
        return 1;
    }

    printf(" %d 的所有因数为:", n);

    // 只遍历到 sqrt(n),提高效率
    int sqrt_n = (int)sqrt(n);

    for (int i = 1; i <= sqrt_n; i++) {
        if (n % i == 0) {  // i 是因数
            printf("%d ", i);  // 输出较小的因数

            // 如果 i 不等于 n/i,说明还有一个对应的因数
            if (i != n / i) {
                printf("%d ", n / i);  // 输出较大的因数
            }
        }
    }

    printf("\n");
    return 0;
}

优化点说明

  • #include <math.h>:引入数学函数库,使用 sqrt() 函数。
  • int sqrt_n = (int)sqrt(n);:计算 n 的平方根,并转为整数,作为循环上限。
  • n % i == 0:判断 i 是否为因数。
  • printf("%d ", i);:输出较小的因数。
  • if (i != n / i):防止重复输出(例如 n = 9 时,3 × 3 = 9,只应输出一次 3)。
  • printf("%d ", n / i);:输出对应的较大因数。

这个版本的时间复杂度从 O(n) 降到了 O(√n),性能提升非常显著。


存储因数:使用数组保存结果

在某些场景下,我们不仅想打印因数,还想对它们进行后续处理,比如排序、求和、判断是否为质数等。这时,将因数存入数组就非常必要。

下面是一个将所有因数存储在数组中的版本:

#include <stdio.h>
#include <math.h>

int main() {
    int n;
    int factors[1000];  // 假设最多有 1000 个因数
    int count = 0;      // 记录因数个数

    printf("请输入一个正整数:");
    scanf("%d", &n);

    if (n <= 0) {
        printf("请输入一个大于 0 的正整数!\n");
        return 1;
    }

    int sqrt_n = (int)sqrt(n);

    for (int i = 1; i <= sqrt_n; i++) {
        if (n % i == 0) {
            factors[count++] = i;  // 存储较小的因数

            // 如果 i 和 n/i 不同,存入较大的因数
            if (i != n / i) {
                factors[count++] = n / i;
            }
        }
    }

    // 输出结果
    printf(" %d 的所有因数为:", n);
    for (int i = 0; i < count; i++) {
        printf("%d ", factors[i]);
    }
    printf("\n");

    return 0;
}

关键点解析

  • int factors[1000];:定义一个容量为 1000 的数组,用于存储因数。
  • int count = 0;:计数器,记录当前已存储的因数个数。
  • factors[count++] = i;:先赋值,再自增,是常见的数组插入技巧。
  • 最后用一个 for 循环遍历数组,打印所有因数。

这个版本更适合需要进一步处理因数的场景,比如求因数和、判断是否为完全数等。


进阶:对因数排序并去重

在某些应用中,因数的顺序很重要。比如我们希望从小到大排列。上面的代码虽然能找出所有因数,但顺序可能混乱(因为先存小的,再存大的)。

我们可以用冒泡排序来整理:

// 在输出前加入排序代码
for (int i = 0; i < count - 1; i++) {
    for (int j = 0; j < count - 1 - i; j++) {
        if (factors[j] > factors[j + 1]) {
            int temp = factors[j];
            factors[j] = factors[j + 1];
            factors[j + 1] = temp;
        }
    }
}

这样就能保证输出是有序的。


实际案例:判断一个数是否为完全数

完全数是指一个数等于它所有真因数(即除了自身以外的因数)之和。

比如 6 的真因数是 1、2、3,和为 6,所以 6 是完全数。

我们可以基于“求因数”的逻辑,轻松实现这个判断:

int sum = 0;
for (int i = 0; i < count; i++) {
    if (factors[i] != n) {  // 排除自身
        sum += factors[i];
    }
}
if (sum == n) {
    printf("%d 是一个完全数!\n", n);
} else {
    printf("%d 不是完全数。\n", n);
}

这正是“C 语言实例 – 求一个整数的所有因数”在实际项目中的典型应用。


总结与建议

“C 语言实例 – 求一个整数的所有因数”看似简单,却包含了编程的核心思维:从暴力解法到优化算法,从输出结果到数据存储与处理

我们从最基础的遍历法出发,逐步引入平方根优化、数组存储、排序处理,最后还拓展到了完全数判断,完整展示了如何将一个简单问题演变为一个实用工具。

对于初学者,建议先理解第一种暴力法,再逐步学习优化技巧。对于中级开发者,可以尝试将该功能封装为函数,支持输入验证、动态数组、异常处理等高级特性。

记住:编程的本质不是写代码,而是解决问题。而“求因数”正是训练这种能力的绝佳起点。

当你下次看到一个数,不再只是“它是多少”,而是能立刻想到“它的因数有哪些”,你就真正掌握了这门语言的思维方式。