Java实现选择题选项乱序算法
前言
在开发在线考试或问答系统时,经常会遇到一个痛点:考生容易通过背诵选项字母(例如“第一题选C,第二题选A”)来作弊或应付考试。
为了解决这个问题,我们需要在系统渲染试卷时,将题目的选项顺序随机打乱。
这里的核心难点在于:选项顺序打乱后,系统必须依然能准确识别出哪一个是正确答案。
这就好比给房间里的物品换门牌号:物品本身没动,只是门上的字母标签换了,但我们需要时刻追踪那个存放“正确答案”的房间现在挂着什么字母。
一、 核心思路
| 原标签 (originalKey) |
新标签 (newKey) |
选项内容 (value) |
是否为正确答案 |
| A |
C |
JAVA2 EE |
否 |
| B |
A |
JAVA2 Card |
否 |
| C |
D |
JAVA2 ME |
否 |
| D |
B |
JAVA2 HE |
✓ → 触发记录 keyNew = "B" |
内容没有动,只是换了门牌号(字母标签)。正确答案的内容跟着走到了 B,所以正确的选项 Key 也同步更新为 B。
二、核心代码实现
为了实现这个功能,我们首先需要一个数据结构来承载选项和答案。
2.1 定义数据承载类 Topic
这个类非常简单,主要用于封装选项的 Map(选项字母 -> 选项内容)和正确的 key。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import java.util.Map;
public class Topic { private Map<String, String> option; private String key;
public Topic() {}
public Topic(Map<String, String> option, String key) { this.option = option; this.key = key; }
public Map<String, String> getOption() { return option; } public void setOption(Map<String, String> option) { this.option = option; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } }
|
2.2 乱序工具类 TopicRandomUtil
这是整个乱序逻辑的引擎。利用 Collections.shuffle() 来实现“摇匀门牌号”的操作。
在 Java 中,HashMap 的 keySet() 是无序的,它既不保证插入顺序,也不保证字母顺序。它仅仅是根据 Key 的哈希值(Hash Code)计算出的数组下标来存放的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import java.util.*;
public class TopicRandomUtil {
static public Topic random(Map<String, String> option, String key) { Set<String> keySet = option.keySet(); ArrayList<String> keyList = new ArrayList<>(keySet); Collections.shuffle(keyList); HashMap<String, String> optionNew = new HashMap<>(); int idx = 0; String answerNew = ""; for (String originKey : keySet) { String newKey = keyList.get(idx++); if (key.equals(originKey)) { answerNew = newKey; } optionNew.put(newKey, option.get(originKey)); }
return new Topic(optionNew, answerNew); } }
|
算法可视化流程:

3. 实际业务场景模拟验证
为了直观看到效果,我们编写一个简单的 main 方法来模拟这个过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import java.util.HashMap; import java.util.Map;
public class ExamSimulation {
public static void main(String[] args) { Map<String, String> originalOptions = new HashMap<>(); originalOptions.put("A", "JAVA2 EE"); originalOptions.put("B", "JAVA2 Card"); originalOptions.put("C", "JAVA2 ME"); originalOptions.put("D", "JAVA2 HE"); String originalKey = "D";
System.out.println("====== 打乱前 ======"); System.out.println("题目选项: " + originalOptions); System.out.println("正确答案: " + originalKey + " -> " + originalOptions.get(originalKey));
Topic randomizedTopic = TopicRandomUtil.random(originalOptions, originalKey);
System.out.println("\n====== 打乱后 ======"); System.out.println("题目选项: " + randomizedTopic.getOption()); System.out.println("正确答案: " + randomizedTopic.getKey() + " -> " + randomizedTopic.getOption().get(randomizedTopic.getKey())); System.out.println("\n验证结果:答案内容是否改变? " + (!originalOptions.get(originalKey).equals(randomizedTopic.getOption().get(randomizedTopic.getKey())) ? "改变了(错误)" : "没改变(正确)")); } }
|
模拟运行输出结果示例:
1 2 3 4 5 6 7 8 9
| ====== 打乱前 ====== 题目选项: {A=JAVA2 EE, B=JAVA2 Card, C=JAVA2 ME, D=JAVA2 HE} 正确答案: D -> JAVA2 HE
====== 打乱后 ====== 题目选项: {A=JAVA2 EE, B=JAVA2 ME, C=JAVA2 HE, D=JAVA2 Card} 正确答案: C -> JAVA2 HE
验证结果:答案内容是否改变? 没改变(正确)
|
总结
通过分离“标签(Key)”和“内容(Value)”,利用 Collections.shuffle() 打乱标签集合,并在重新绑定的过程中通过内容比对找回正确答案的新标签。