C语言实例_1之从4个不重复的数中,找出3个不重复的数的集合

题目

有 1、2、3、4 四个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

分析

可填在百位、十位、个位的数字都是 1、2、3、4,组成所有的排列后再去掉不满足条件的排列。

实例代码

cpp 复制代码
#include<stdio.h>
// 程序入口 
int main()
{
	// [0] 定义了三个整型变量 `i`、`j` 和 `k`,它们将分别用于表示三位数的百位、十位和个位上的数字
    int i = 0;
    int j = i;
    int k = i;
    // [0]
    // [1] 输出`换行`
    printf("\n");
    // [1]
    // [2] 以下为三重循环
    // [3] 遍历百位上可能出现的数字,从 `1` 开始,到 `4` 结束(因为题目给定的数字是 `1`、`2`、`3`、`4`),每次循环 `i` 的值都会改变,代表不同的百位数字
    for(i = 1; i < 5; i++) { 
        // [4] 遍历十位上可能出现的数字,同样是从 `1` 到 `4`
        for(j = 1; j < 5; j++) {
            // [5] 遍历个位上可能出现的数字,同样是从 `1` 到 `4`
            for (k = 1; k < 5; k++) {
            	// [6] 确保i、j、k三位数互不相同
                if ( (i!=k) && (i!=j) && (j!=k) ) { 
                	// [7] `printf` 函数中的 `%d%d%d ` 是格式化输出的占位符,分别对应 `i`、`j`、`k` 这三个变量的值,输出时会按照顺序将它们组成一个三位数并打印出来,每个三位数后面跟着一个空格
                    printf("%d,%d,%d ", i, j, k);
                    // [7]
                }
                // [6]
            }
            // [5]
        }
        // [4]
    }
    // [3]
    // [2]
    // 程序正常结束
    return 0;
}

以上实例代码存在以下两点可优化的方面:

  • 1.存在多余比较 :在最内层的循环判断条件中,每次都要进行三次比较(i!=k) && (i!=j) && (j!=k)来确保三个数字互不相同。实际上,在外层循环已经对百位和十位数字做了一定的限制(比如百位从14依次取值,十位在每次百位确定后也从14取值且与百位不同),所以到内层判断个位数字时,有些比较是多余的。例如,当百位是1,十位是2时,在判断个位数字时其实只需要判断个位数字不等于1且不等于2即可,而不需要再判断十位不等于百位这种已经确定的情况,这会导致一些不必要的计算开销,尤其在处理更复杂的数字组合或数字范围更大时,这种多余的比较可能会累积影响效率。
  • 2.未利用已有条件优化循环范围 :在每个循环中,都是从14进行完整的遍历。可以考虑根据前面已经确定的数字来缩小后续循环的范围,比如十位数字的循环可以从百位数字+1开始(确保与百位不同且能减少循环次数),个位数字的循环也可以根据百位和十位数字进一步优化范围,这样能减少不必要的循环迭代次数,从而提高运行效率。

优化方法1之减少不必要的循环次数

在实例代码中,内层循环每次都要从 1 遍历到 4,即使前面已经确定了百位和十位数字,有些情况是可以提前判断并跳过不必要的循环的。

十位数字的循环从 i + 1 开始,这样就避免了重复判断十位数字等于百位数字的情况,减少了一些不必要的循环次数。

cpp 复制代码
#include <stdio.h>

int main() {
    int i, j, k;

    // 百位数字的循环
    for (i = 1; i < 5; i++) {
        // 十位数字的循环,注意要和百位数字不同
        for (j = 1; j < 5; j++) {
            if (j!= i) {
                // 个位数字的循环,要和百位、十位数字都不同
                for (k = 1; k < 5; k++) {
                    if (k!= i && k!= j) {
                        // 输出满足条件的三位数
                        printf("%d%d%d ", i, j, k);
                    }
                }
            }
        }
    }

    return 0;
}

优化方法2之使用位运算进行标记

利用位运算来标记已经使用过的数字,从而快速判断是否满足无重复数字的条件。

通过位运算来快速判断数字是否已经被使用过,相比于原始代码中的多次条件判断,在某些情况下可能会提高执行效率,尤其是当需要处理的数字范围较大且重复判断较多时,位运算的优势会更加明显。不过这种方法相对来说理解起来可能会稍微复杂一些。

cpp 复制代码
#include <stdio.h>

int main() {
    int i, j, k;

    // 百位数字的循环,从1到4
    for (i = 1; i < 5; i++) {
        // 使用位运算标记百位数字已经被使用
        int used = 1 << (i - 1);

        // 十位数字的循环,从1到4
        for (j = 1; j < 5; j++) {
            // 如果十位数字未被使用(通过位运算判断)
            if (!(used & (1 << (j - 1)))) {
                // 更新位标记,表示十位数字也被使用了
                used |= (1 << (j - 1));

                // 个位数字的循环,从1到4
                for (k = 1; k < 5; k++) {
                    // 如果个位数字未被使用(通过位运算判断)
                    if (!(used & (1 << (k - 1)))) {
                        // 输出满足条件的三位数
                        printf("%d%d%d ", i, j, k);
                    }
                }

                // 清除十位数字的位标记,以便下一次十位数字循环时重新判断
                used &= ~(1 << (j - 1));
            }
        }
    }

    return 0;
}

输出结果

cpp 复制代码
123 124 132 134 142 143 213 214 231 234 241 243 312 314 321 324 341 342 412 413 421 423 431 432 

高价出售本人脑子没有用过有意者私。

相关推荐
是小胡嘛1 小时前
C++之Any类的模拟实现
linux·开发语言·c++
口袋物联2 小时前
设计模式之工厂模式在 C 语言中的应用(含 Linux 内核实例)
linux·c语言·设计模式·简单工厂模式
csbysj20202 小时前
Vue.js 混入:深入理解与最佳实践
开发语言
Gerardisite4 小时前
如何在微信个人号开发中有效管理API接口?
java·开发语言·python·微信·php
Want5954 小时前
C/C++跳动的爱心①
c语言·开发语言·c++
lingggggaaaa4 小时前
免杀对抗——C2远控篇&C&C++&DLL注入&过内存核晶&镂空新增&白加黑链&签名程序劫持
c语言·c++·学习·安全·网络安全·免杀对抗
coderxiaohan4 小时前
【C++】多态
开发语言·c++
gfdhy4 小时前
【c++】哈希算法深度解析:实现、核心作用与工业级应用
c语言·开发语言·c++·算法·密码学·哈希算法·哈希
Eiceblue5 小时前
通过 C# 将 HTML 转换为 RTF 富文本格式
开发语言·c#·html
故渊ZY5 小时前
Java 代理模式:从原理到实战的全方位解析
java·开发语言·架构