Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
生成随机矩阵并控制元素重复次数的教程_创想鸟

生成随机矩阵并控制元素重复次数的教程

生成随机矩阵并控制元素重复次数的教程

本教程将详细介绍如何在java中生成一个指定大小的随机矩阵,并确保矩阵中的每个元素都按照预设的频率(例如,每个元素出现两次)出现。文章将通过构建一个包含所需元素的初始数组,并利用fisher-yates洗牌算法对其进行随机化,然后将洗牌后的元素填充到矩阵中,从而解决直接使用随机数生成器难以控制元素重复次数的问题。

1. 引言:受控随机性的挑战

在编程中,我们经常需要生成随机数据。然而,当需求不仅仅是“随机”那么简单,还需要对随机结果的分布或元素的重复次数进行精确控制时,传统的随机数生成方法(如Random.nextInt())往往力不从心。例如,如果我们需要创建一个4×4的矩阵,其中包含1到8的数字,并且要求每个数字恰好出现两次,直接使用r.nextInt(8)并不能保证这一条件。每次生成的数字都是独立的,可能导致某些数字出现多次,而另一些数字则完全缺失或只出现一次。

考虑以下初始尝试代码,它无法满足上述要求:

import java.util.Arrays;import java.util.Random;public class RandomMatrixProblem {    public static void main(String[] args) {        int[][] mat = new int[4][4];        Random r = new Random();        for(int i = 0; i < 4; i++){            for(int j = 0; j < 4; j++){                // 这种方法无法控制数字的出现次数                mat[i][j] = r.nextInt(8) + 1; // 假设范围是1-8            }        }        for(int i=0; i<4; i++){            System.out.println(Arrays.toString(mat[i]));        }    }}

运行上述代码,你会发现生成的矩阵中数字的分布是完全随机的,无法保证1到8的每个数字都出现两次。

2. 解决方案策略:预设元素池与洗牌算法

要解决受控随机性问题,核心思想是“先准备,后打乱”。我们不直接向矩阵中填充随机数,而是首先创建一个包含所有所需元素的“池”,并确保每个元素在池中出现的次数符合要求。然后,我们对这个池进行随机洗牌,最后按照顺序将洗牌后的元素填充到矩阵中。

对于本例,目标是创建一个4×4矩阵(共16个元素),其中包含1到8的数字,且每个数字出现两次。这意味着我们的元素池应该包含[1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8]。

然而,更巧妙且高效的策略是:

创建一个包含1到8所有数字的基准数组([1, 2, 3, 4, 5, 6, 7, 8])。对这个基准数组进行第一次洗牌。使用洗牌后的数组的前8个元素填充矩阵的前8个位置(例如,前两行)。对同一个基准数组进行第二次洗牌。使用第二次洗牌后的数组的前8个元素填充矩阵的后8个位置(例如,后两行)。

通过这种方式,我们可以确保1到8的每个数字在矩阵的前半部分出现一次,在后半部分也出现一次,从而达到每个数字出现两次的总目标,并且每次运行都能得到不同的随机排列

3. 实现洗牌算法(Fisher-Yates)

洗牌算法是实现随机化的关键。Fisher-Yates(或Knuth)洗牌算法是一种高效且公平的算法,用于将有限序列随机排列。其基本思想是从数组的最后一个元素开始,将其与数组中随机选取的任何一个元素(包括它自己)进行交换,然后对剩余的元素重复此过程,直到第一个元素。

闪念贝壳 闪念贝壳

闪念贝壳是一款AI 驱动的智能语音笔记,随时随地用语音记录你的每一个想法。

闪念贝壳 218 查看详情 闪念贝壳

以下是实现Fisher-Yates洗牌算法的Java方法:

import java.util.Random;public class ArrayShuffler {    /**     * 使用Fisher-Yates算法随机打乱一个整数数组。     * @param data 待打乱的整数数组。     * @return 打乱后的数组。     */    public static int[] randomizeArray(int[] data) {        Random r = new Random();        for (int i = data.length - 1; i > 0; i--) { // 从最后一个元素向前遍历            int randomIndexSwap = r.nextInt(i + 1); // 生成一个0到i(包括i)之间的随机索引            // 交换当前元素与随机索引处的元素            int temp = data[randomIndexSwap];            data[randomIndexSwap] = data[i];            data[i] = temp;        }        return data;    }}

注意事项:

r.nextInt(i + 1)确保了随机索引的范围是从0到当前未洗牌部分的末尾(i)。循环条件i > 0意味着最后一个元素(索引为0)不需要再与任何元素交换,因为它是唯一剩下的未洗牌元素。

4. 构建具有指定重复次数的矩阵

现在,我们将结合洗牌算法和上述策略来构建目标矩阵。

import java.util.Arrays;import java.util.Random;public class RandomMatrixGenerator {    /**     * 使用Fisher-Yates算法随机打乱一个整数数组。     * @param data 待打乱的整数数组。     * @return 打乱后的数组。     */    public static int[] randomizeArray(int[] data) {        Random r = new Random();        for (int i = data.length - 1; i > 0; i--) {            int randomIndexSwap = r.nextInt(i + 1);            int temp = data[randomIndexSwap];            data[randomIndexSwap] = data[i];            data[i] = temp;        }        return data;    }    public static void main(String[] args) {        int[][] mat = new int[4][4];        // 初始数据数组,包含1到8的唯一数字        int[] data = {1, 2, 3, 4, 5, 6, 7, 8};        // 第一次打乱数组,用于填充矩阵的前两行        data = randomizeArray(data);        for (int i = 0; i < 4; i++) {            // 当i达到2时(即开始填充第三行之前),再次打乱数组            if (i == 2) {                data = randomizeArray(data); // 第二次打乱数组,用于填充矩阵的后两行            }            for (int j = 0; j < 4; j++) {                // 根据行索引i和列索引j计算data数组中的对应位置                // (i % 2) * 4:                //   - 当 i = 0 或 2 时, i % 2 = 0, (i % 2) * 4 = 0                //   - 当 i = 1 或 3 时, i % 2 = 1, (i % 2) * 4 = 4                // 这样,对于每两行,我们使用data数组中的前8个元素                // (0-3索引用于第一行/第三行,4-7索引用于第二行/第四行)                mat[i][j] = data[(i % 2) * 4 + j];            }        }        // 打印生成的矩阵        for (int i = 0; i < 4; i++) {            System.out.println(Arrays.toString(mat[i]));        }    }}

4.1 代码逻辑详解

int[][] mat = new int[4][4];: 初始化一个4×4的整数矩阵。int[] data = {1, 2, 3, 4, 5, 6, 7, 8};: 创建一个包含1到8的基准数组。这个数组在整个过程中会被重复洗牌和使用。data = randomizeArray(data);: 第一次调用randomizeArray方法,将data数组随机打乱。这个打乱后的数组将用于填充矩阵的第一行和第二行。外层循环 for (int i = 0; i < 4; i++): 遍历矩阵的行。if (i == 2) { data = randomizeArray(data); }: 这是一个关键步骤。当行索引i等于2时(即即将开始填充第三行),data数组会被再次打乱。这意味着第三行和第四行将使用一个全新的随机排列。内层循环 for (int j = 0; j < 4; j++): 遍历矩阵的列。*`mat[i][j] = data[(i % 2) 4 + j];**: 这是将data数组中的元素映射到mat`矩阵中的核心逻辑。(i % 2): 当i为0或2时,结果为0;当i为1或3时,结果为1。*`(i % 2) 4`**:当i为0或2时,结果为0。当i为1或3时,结果为4。data[…]:对于 i = 0 (第一行): mat[0][j] = data[0 * 4 + j] = data[j]。这会使用data数组的前4个元素 (data[0]到data[3]) 填充第一行。对于 i = 1 (第二行): mat[1][j] = data[1 * 4 + j] = data[4 + j]。这会使用data数组的后4个元素 (data[4]到data[7]) 填充第二行。至此,矩阵的前两行 (mat[0]和mat[1]) 已经填充完毕,它们共同包含了第一次洗牌后data数组的所有8个唯一元素。对于 i = 2 (第三行): data数组被第二次洗牌。然后 mat[2][j] = data[0 * 4 + j] = data[j]。这会使用第二次洗牌后data数组的前4个元素 (data[0]到data[3]) 填充第三行。对于 i = 3 (第四行): mat[3][j] = data[1 * 4 + j] = data[4 + j]。这会使用第二次洗牌后data数组的后4个元素 (data[4]到data[7]) 填充第四行。至此,矩阵的后两行 (mat[2]和mat[3]) 也已填充完毕,它们共同包含了第二次洗牌后data数组的所有8个唯一元素。

通过这种精巧的索引和两次洗牌机制,我们确保了1到8的每个数字在整个4×4矩阵中恰好出现两次。

5. 泛化与扩展

上述解决方案是针对4×4矩阵和1-8数字出现两次的特定情况进行了优化。要将其泛化到不同大小的矩阵、不同的数字范围或不同的重复次数,可以采用以下更通用的方法:

确定矩阵总元素数:totalElements = rows * columns。确定唯一数字的数量:numUnique = maxVal – minVal + 1。计算每个数字应出现的次数:occurrencesPerNum = totalElements / numUnique。注意:totalElements 必须是 numUnique 的整数倍,否则无法实现每个数字出现相同次数。构建完整的元素池:创建一个大小为 totalElements 的数组。遍历 minVal 到 maxVal,将每个数字重复 occurrencesPerNum 次添加到这个数组中。一次性洗牌:对这个完整的元素池数组进行一次Fisher-Yates洗牌。填充矩阵:按照顺序将洗牌后的元素池中的元素填充到矩阵中。

示例泛化代码结构:

import java.util.Arrays;import java.util.Random;public class GenericRandomMatrixGenerator {    public static int[] randomizeArray(int[] data) {        Random r = new Random();        for (int i = data.length - 1; i > 0; i--) {            int randomIndexSwap = r.nextInt(i + 1);            int temp = data[randomIndexSwap];            data[randomIndexSwap] = data[i];            data[i] = temp;        }        return data;    }    public static int[][] generateMatrix(int rows, int cols, int minVal, int maxVal, int occurrences) {        int totalElements = rows * cols;        int numUnique = maxVal - minVal + 1;        if (totalElements % numUnique != 0 || totalElements / numUnique != occurrences) {            throw new IllegalArgumentException("无法满足所有数字出现指定次数的条件。请检查矩阵大小、数字范围和出现次数。");        }        // 构建完整的元素池        int[] elementPool = new int[totalElements];        int poolIndex = 0;        for (int val = minVal; val <= maxVal; val++) {            for (int k = 0; k < occurrences; k++) {                elementPool[poolIndex++] = val;            }        }        // 洗牌元素池        elementPool = randomizeArray(elementPool);        // 填充矩阵        int[][] matrix = new int[rows][cols];        int currentPoolIndex = 0;        for (int i = 0; i < rows; i++) {            for (int j = 0; j < cols; j++) {                matrix[i][j] = elementPool[currentPoolIndex++];            }        }        return matrix;    }    public static void main(String[] args) {        // 生成一个4x4矩阵,元素1-8,每个出现2次        int[][] myMatrix = generateMatrix(4, 4, 1, 8, 2);        for (int i = 0; i < myMatrix.length; i++) {            System.out.println(Arrays.toString(myMatrix[i]));        }        // 示例:生成一个3x3矩阵,元素1-3,每个出现3次        // int[][] anotherMatrix = generateMatrix(3, 3, 1, 3, 3);        // System.out.println("\nAnother Matrix (3x3, 1-3, each 3 times):");        // for (int i = 0; i < anotherMatrix.length; i++) {        //     System.out.println(Arrays.toString(anotherMatrix[i]));        // }    }}

6. 总结

通过本教程,我们学习了如何利用预设元素池和Fisher-Yates洗牌算法来生成具有受控元素重复次数的随机矩阵。这种方法比直接使用Random.nextInt()更为可靠和精确,尤其适用于需要严格控制数据分布的场景。无论是特定大小的矩阵,还是需要泛化的解决方案,核心思想都是先构建一个符合所有条件的元素序列,然后对其进行彻底的随机化,最后按顺序填充到目标结构中。

以上就是生成随机矩阵并控制元素重复次数的教程的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1053577.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Yandex浏览器官网在线版入口 Yandex浏览器网页版最新官网
上一篇 2025年12月2日 04:44:20
mysql自动获取时间日期的方法
下一篇 2025年12月2日 04:44:21

相关推荐

  • Java中用户输入验证:正确使用equals()或转换为整数进行比较

    本教程详细阐述了Java中用户输入字符串(如菜单选项)验证的正确方法。针对==运算符在字符串比较中的局限性,文章介绍了两种解决方案:一是使用String.equals()方法进行内容比较,二是将字符串输入解析为整数后进行数值比较。通过代码示例,帮助开发者避免常见的字符串比较错误,确保程序逻辑的健壮性…

    2026年9月23日
    000
  • 微软免费文件恢复工具介绍

    微软免费文件恢复工具介绍微软免费文件恢复工具介绍微软免费文件恢复工具介绍微软免费文件恢复工具介绍

    现在好了,最近微软在 windows 10 应用商店中上架了一款免费的数据删除恢复工具 windows file recovery,猿妹再也不用担心误删文件了。 Windows File Recovery基于命令行程序设计,大小仅有8.26MB,所有Windows 10用户均可免费下载使用。 无论是…

    2026年9月23日 用户投稿
    000
  • VSCode精简配置Perl:语法检查、中文编码、正则调试

    vscode中perl语法检查不生效的主要原因是perl解释器路径未正确配置或缺失,解决方法是在settings.json中明确设置”perl.perlpath”指向正确的perl可执行文件;其次是因缺少cpan模块导致检查失败,需安装对应模块;此外,多个perl扩展冲突、大…

    2026年9月23日
    000
  • AfterEffects如何制作AI动效视频?创建动态AI视频的完整教程

    AfterEffects如何制作AI动效视频?创建动态AI视频的完整教程AfterEffects如何制作AI动效视频?创建动态AI视频的完整教程AfterEffects如何制作AI动效视频?创建动态AI视频的完整教程AfterEffects如何制作AI动效视频?创建动态AI视频的完整教程

    答案是掌握AE动画原理并融合AI素材进行创作。需根据风格选择合适AI工具(如Midjourney、RunwayML),注重素材质量、可定制性与透明背景支持;将AI素材导入AE后,调整分辨率,运用颜色校正、模糊、跟踪及表达式增强效果;通过关键帧控制位置、缩放、旋转,并应用缓动实现流畅动画;搭配契合主题…

    2026年9月23日 用户投稿
    200
  • 如何在Java中安装Eclipse开发环境

    先安装JDK并配置环境变量,再下载安装Eclipse IDE。1. 安装JDK:从Oracle或Eclipse Adoptium下载JDK 17/21,按提示安装,设置JAVA_HOME和PATH,用java -version验证。2. 安装Eclipse:官网下载“Eclipse IDE for …

    2026年9月23日
    000
  • 配置Linux下vim自动缩进

    从终端打开配置文件: vim ~/.vimrc 添加如下代码: set tabstop=4set softtabstop=4set shiftwidth=4set autoindentset cindentset cinoptions={0,1s,t0,n-2,p2s,(03s,=.5s,>1…

    2026年9月23日
    800
  • 2025 旗舰手机选购指南:四款机型精准匹配你的需求

    2025 旗舰手机选购指南:四款机型精准匹配你的需求2025 旗舰手机选购指南:四款机型精准匹配你的需求2025 旗舰手机选购指南:四款机型精准匹配你的需求2025 旗舰手机选购指南:四款机型精准匹配你的需求

    在智能手机市场持续繁荣的今天,面对琳琅满目的旗舰%ignore_a_1%,用户往往难以抉择。本文精选四款当前热门的高端手机,帮你高效锁定心仪之选。 1 五款旗舰机型推荐 1. OPPO Find X9 系列 大容量电池、护眼显示屏、双 2 亿像素影像系统——适合对续航敏感、热爱摄影以及重视视觉健康的…

    2026年9月23日 用户投稿
    200
  • VSCode如何实现AI辅助编程 VSCode Copilot插件的深度使用指南

    github copilot能显著提升编程效率,但需合理使用。1. 安装插件并登录github账号是基础步骤;2. 提供清晰的上下文,如规范命名和详细注释,可提高生成代码的准确性;3. 利用快捷键切换多个建议,筛选最优方案并进行修改;4. 对生成代码必须严格审查,尤其关注安全性与业务逻辑匹配度;5.…

    2026年9月23日
    100
  • 抖音ai分身怎么弄出来?抖音分身在哪里打开

    随着人工智能技术不断发展,其应用已经深入到我们日常生活的诸多领域。作为当前热门的短视频平台之一,抖音也推出了AI分身功能,让用户可以轻松创建属于自己的虚拟形象。本文将为您详细介绍抖音AI分身的操作方法,助您在抖音平台上脱颖而出! 一、了解抖音AI分身 抖音AI分身是一项基于人工智能算法打造的特效功能…

    2026年9月23日
    000
  • Java岗大厂面试百日冲刺 – 日积月累,每日三题【Day25】—— JVM1

    Java岗大厂面试百日冲刺 – 日积月累,每日三题【Day25】—— JVM1Java岗大厂面试百日冲刺 – 日积月累,每日三题【Day25】—— JVM1Java岗大厂面试百日冲刺 – 日积月累,每日三题【Day25】—— JVM1Java岗大厂面试百日冲刺 – 日积月累,每日三题【Day25】—— JVM1

    车票 面试题1:你遇到过哪些OOM情况,什么原因造成的?怎么解决的? 该问题主要针对你遇到的实际问题出发,可以根据你实际遇到过的情况和场景,结合下面每种情况的具体原因和解决方式,整理后回答。 当堆内存(Heap Space)没有足够空间存放新创建的对象时,就会抛出 java.lang.OutOfMe…

    2026年9月23日 用户投稿
    000
  • 如何用PhotoPosPro的AI裁剪图片?快速实现智能裁剪的教程

    PhotoPosPro的AI裁剪功能可自动识别图片主体并裁剪边缘,适合快速处理或构图新手。打开图片后,在“Image”或“Tools”菜单中找到“AI Crop”工具,可选裁剪比例或让软件自动判断,点击“Apply”运行AI裁剪。完成后可手动微调裁剪框,满意后保存。若效果不佳,可尝试手动调整、切换A…

    2026年9月23日
    200
  • 为什么Java中构造方法重要 如何正确编写构造方法

    构造方法确保对象正确初始化:通过强制赋初值、校验数据、支持封装和重载提升灵活性;编写时需遵循命名一致、无返回类型、合理用参、注意访问修饰符、避免复杂逻辑及善用this()调用;常见误区包括忽略无参构造、过度初始化和异常处理不当。 构造方法在Java中扮演着初始化对象的关键角色。创建对象时,构造方法会…

    2026年9月23日
    000
  • VS Code团队协作:共享配置与规范

    通过共享VS Code配置实现团队协作标准化,1. 使用.settings.json统一编辑器行为;2. 集成Prettier与ESLint确保代码风格一致;3. 通过extensions.json推荐必备插件;4. 忽略私有配置文件避免冲突,提升开发效率。 在团队开发中,保持代码风格一致和开发环境…

    2026年9月23日
    000
  • 苹果官网正版查询系统 iPhone序列号验证正品平台

    苹果官网正品查询入口为https://checkcoverage.apple.com/cn/zh/,输入序列号可验证设备型号、保修状态、购买方式及激活锁等信息,确保设备真实性与安全性。 苹果官网正版查询系统 iPhone序列号验证正品平台在哪里?这是不少网友都关注的,接下来由PHP小编为大家带来苹果…

    2026年9月23日
    000
  • Prestashop分类描述在分页时的显示行为解析与SEO考量

    Prestashop商店中,分类描述通常仅在首个分页页面显示,而在后续分页页面上消失,甚至从第二页返回第一页时也可能不显示。这并非一个技术故障,而是Prestashop的默认行为,且从SEO角度看,只要描述在直接访问的第一页可见,就已满足核心要求,无需在所有分页页面重复显示,以避免潜在的重复内容问题…

    2026年9月23日
    100
  • 手把手教你在 Ubuntu16.04 安装 GPU 驱动 + CUDA9.0 + cuDNN7

    手把手教你在 Ubuntu16.04 安装 GPU 驱动 + CUDA9.0 + cuDNN7手把手教你在 Ubuntu16.04 安装 GPU 驱动 + CUDA9.0 + cuDNN7手把手教你在 Ubuntu16.04 安装 GPU 驱动 + CUDA9.0 + cuDNN7手把手教你在 Ubuntu16.04 安装 GPU 驱动 + CUDA9.0 + cuDNN7

    如果你的电脑上安装了 ubuntu 16.04 系统,并且配备了一块 nvidia geforce gpu 显卡,那么不利用它来运行深度学习模型就太可惜了!尽管网上有许多相关教程,但质量参差不齐。本文将详细指导你如何在 ubuntu 16.04 上安装 gpu 显卡驱动、cuda 9.0 和 cud…

    2026年9月23日 用户投稿
    000
  • Infinispan中实现并发安全计数器:解决分布式应用中的用户登录统计挑战

    本文探讨了在Infinispan缓存中实现并发安全的用户登录计数问题,当多个用户同时登录时,传统计数方式可能导致数据不一致。文章详细介绍了利用Infinispan提供的分布式计数器、事务机制和版本化操作这三种核心策略,以确保在高并发环境下数据更新的原子性和一致性,为构建健壮的分布式应用提供解决方案。…

    2026年9月23日
    200
  • Hibernate实体间非映射关联ID的引用与查询策略

    本文探讨了在Hibernate应用中,如何在不建立显式实体映射关系(如@ManyToOne)的情况下,实现实体间基于ID的引用和数据查询。核心方法是利用HQL/JPQL的JOIN…ON语法,通过共享的ID字段进行动态关联查询,从而简化实体模型设计,避免不必要的复杂映射,同时满足数据追踪和…

    2026年9月23日
    400
  • Java对象与引用的区别是什么 引用传递对方法调用的影响

    对象是类的实例,存储在堆中;引用是保存对象地址的变量,存储在栈或堆中。例如Person p = new Person();中,new Person()创建对象在堆中,p是引用,指向该对象。Java只有值传递:基本类型传值,引用类型传地址副本。方法参数接收引用副本,仍指向同一对象,因此可通过它修改对象…

    2026年9月23日
    800
  • WooCommerce 新订单邮件:根据运输方式设置回复邮箱

    本文介绍了如何根据 WooCommerce 订单中的运输方式,动态设置新订单邮件的回复邮箱。通过自定义 wp_mail 钩子,可以实现更精细化的邮件管理,将不同运输方式的客户咨询路由到相应的邮箱地址,提高客户服务的效率。 根据运输方式自定义 WooCommerce 新订单邮件回复邮箱 WooComm…

    2026年9月23日
    000

发表回复

登录后才能评论
关注微信