You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在4×4二维数组生成无重复随机数?现有C代码仍输出重复求排查

代码错误分析及修正方案

核心错误点

1. 重复检查范围严重缺失

在检查已填入元素是否重复时,代码对**当前行之前的行(k < i)**仅检查到l <= j的列,完全漏掉了这些行中列号大于j的元素。比如填充第1行第0列(i=1,j=0)时,第0行的第1、2、3列元素根本没被检查,导致生成的随机数如果和这些元素重复,代码无法识别,最终出现重复值。

正确的检查逻辑应该是:

  • 对k < i的行:遍历该行所有4列(l从0到3)
  • 对k == i的行:只遍历到当前列的前一列(l从0到j-1),避免检查刚赋值的当前元素

2. 重复处理逻辑无效

当发现重复时,代码仅执行j--后break,但外层j循环会自动执行j++,直接抵消j--的效果,回到原位置。更关键的是,这种处理没有重新生成随机数并再次校验,即便重新进入循环生成新数,也会因为检查范围的缺失依然可能出现重复。

另外,代码先赋值再检查的逻辑不合理,应该先确认随机数不重复,再赋值给数组元素。

3. 冗余的当前元素判断

代码中if(k != i && l != j)的判断完全多余——只要调整检查范围,让当前行只遍历到j-1列,就不会检查到刚赋值的当前元素,反而增加了逻辑复杂度。


修正后的代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    int A[4][4];
    int i, j, k, l;
    int num;
    int is_duplicate;

    srand(time(NULL));

    for(i = 0; i < 4; i++)
    {
        for(j = 0; j < 4; j++)
        {
            do {
                is_duplicate = 0;
                num = rand() % 16 + 1;

                // 检查所有已填满的行
                for(k = 0; k < i; k++)
                {
                    for(l = 0; l < 4; l++)
                    {
                        if(A[k][l] == num)
                        {
                            is_duplicate = 1;
                            break;
                        }
                    }
                    if(is_duplicate) break;
                }

                // 检查当前行已填入的前几列
                if(!is_duplicate)
                {
                    for(l = 0; l < j; l++)
                    {
                        if(A[i][l] == num)
                        {
                            is_duplicate = 1;
                            break;
                        }
                    }
                }
            } while(is_duplicate); // 重复生成直到得到不重复的数

            A[i][j] = num;
        }
    }

    // 输出数组
    for(i = 0; i < 4; i++)
    {
        for(j = 0; j < 4; j++)
        {
            printf("%3d", A[i][j]);
        }
        printf("\n");
    }

    return 0;
}

更高效的实现思路

上面的方法是生成随机数后校验重复,当数组接近填满时,重复概率会升高,效率较低。更优的方式是先创建1-16的有序数组,用Fisher-Yates洗牌算法打乱顺序,再填入二维数组:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    int arr[16];
    int A[4][4];
    int i, j, temp, random_idx;

    // 初始化有序数组
    for(i = 0; i < 16; i++)
    {
        arr[i] = i + 1;
    }

    srand(time(NULL));

    // Fisher-Yates洗牌:从后往前交换随机位置的元素
    for(i = 15; i > 0; i--)
    {
        random_idx = rand() % (i + 1);
        temp = arr[i];
        arr[i] = arr[random_idx];
        arr[random_idx] = temp;
    }

    // 转换为4×4二维数组
    for(i = 0; i < 4; i++)
    {
        for(j = 0; j < 4; j++)
        {
            A[i][j] = arr[i * 4 + j];
        }
    }

    // 输出结果
    for(i = 0; i < 4; i++)
    {
        for(j = 0; j < 4; j++)
        {
            printf("%3d", A[i][j]);
        }
        printf("\n");
    }

    return 0;
}

这种方法确保所有数字不重复,且时间复杂度更低,适合元素数量较多的场景。

内容的提问来源于stack exchange,提问作者mouin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 09:35:21