Java 描述这种随机但公平地调用学生的程序/算法的正确术语是什么?

Java 描述这种随机但公平地调用学生的程序/算法的正确术语是什么?,java,c#,algorithm,random,data-structures,Java,C#,Algorithm,Random,Data Structures,作为一名教师,我想设计一个程序,帮助我随机拜访学生。随机数生成器不够好,因为很少有学生会用这种方式被调用。我也不想要一个随机的队列生成器,因为这样一来,我刚拜访的一个学生就可以自信地停止关注,直到我拜访她的其他同学 理想情况下,我可以使用某种程序在随机队列中调用1-10名学生,但偶尔会偏离该队列调用以前调用的学生。这将确保所有学生都能合理频繁地被拜访,但最近被拜访的学生不会因为我暂时不再拜访他而自满。例如,像这样的随机输出就是我需要的:5,7,2,1,1,9,10,5,3,6,8,9,4 描述这

作为一名教师,我想设计一个程序,帮助我随机拜访学生。随机数生成器不够好,因为很少有学生会用这种方式被调用。我也不想要一个随机的队列生成器,因为这样一来,我刚拜访的一个学生就可以自信地停止关注,直到我拜访她的其他同学

理想情况下,我可以使用某种程序在随机队列中调用1-10名学生,但偶尔会偏离该队列调用以前调用的学生。这将确保所有学生都能合理频繁地被拜访,但最近被拜访的学生不会因为我暂时不再拜访他而自满。例如,像这样的随机输出就是我需要的:5,7,2,1,1,9,10,5,3,6,8,9,4

描述这种程序的正确术语是什么?我不一定要寻找关于如何编写此类代码的答案,尽管这也很好。

您可以选择 例如:

public class Program {

    static void shuffle(int[] array) {
        int n = array.length;
        Random random = new Random();
        for (int i = 0; i < array.length; i++) {
            int randomValue = i + random.nextInt(n - i);
            int randomElement = array[randomValue];
            array[randomValue] = array[i];
            array[i] = randomElement;
        }
    }

    public static void main(String[] args) {

        int[] values = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        shuffle(values);

        // Display elements in array.
        for (int value : values) {
            System.out.println(value);
        }
    }
}
公共类程序{
静态空洗牌(int[]数组){
int n=数组长度;
随机=新随机();
for(int i=0;i
您可以从调用池中选择学生,在调用池中,每个学生都被表示一定次数。为了消除呼叫不一致性,此池中出现的次数对于选择次数较少的学生较高,而对于选择次数较多的学生较小,但不少于1次,以便让任何学生在任何时候都有机会再次被呼叫,而不考虑其“呼叫历史”。最初,每个学生在池中只代表一次。以下实施允许学生的热包含/排除。生成器由
nextCall()
方法提供

import java.util.*;
import java.security.SecureRandom;

public class StudentCalls {
    private final Set<String> students = new HashSet<>();
    private final List<String> callPool = new ArrayList<>();
    private static final Random rand = new SecureRandom();

    public void addStudent(String name) {
        int studentCount = students.size();
        if (!students.add(name))
            throw new IllegalArgumentException(name + " has already been added");
        int newStudentCalls = studentCount == 0 ? 1 // bootstrap
                // average of already present students', never less than 1
                : (int) Math.round((double) callPool.size() / studentCount);
        for (int i = 1; i <= newStudentCalls; i++)
            callPool.add(name);
    }

    public void addStudents(String... names) {
        for (String name : names)
            addStudent(name);
    }

    public void removeStudent(String name) {
        if (!students.remove(name))
            throw new IllegalArgumentException("Unknown student: " + name);
        callPool.removeAll(Collections.singleton(name));
    }

    public String nextCall() {
        int poolSize = callPool.size();
        if (poolSize == 0)
            throw new IllegalStateException("No students to choose from");
        int poolIndex = rand.nextInt(poolSize);
        /* Below is optimized equivalent of this code:
        String selectedStudent = callPool.remove(poolIndex);
        if (!callPool.contains(selectedStudent))
            callPool.addAll(students);
        */
        String selectedStudent = callPool.get(poolIndex);
        if (Collections.frequency(callPool, selectedStudent) > 1) {
            String lastInPool = callPool.remove(--poolSize);
            if (poolIndex < poolSize)
                callPool.set(poolIndex, lastInPool);
        } else
            for (String student : students)
                if (!student.equals(selectedStudent))
                    callPool.add(student);
        return selectedStudent;
    }

    public void conductClasses(int numberOfCalls) {
        for (int i = 0; i < numberOfCalls; i++)
            System.out.println(nextCall());
        System.out.println();
    }

    public static void main(String[] args) {
        StudentCalls sc = new StudentCalls();
        sc.addStudents("Josh", "Cooper", "Rachel", "Buckley", "Matt",
                "Lucy", "Kristin", "Kyle", "Kelly");
        sc.conductClasses(20);
        sc.removeStudent("Matt");
        sc.conductClasses(15);
        sc.addStudent("Cliff");
        sc.conductClasses(25);
    }
}
import java.util.*;
导入java.security.SecureRandom;
公开课学生电话{
私有最终集学生=新HashSet();
private final List callPool=new ArrayList();
private static final Random rand=new SecureRandom();
public void addStudent(字符串名称){
int studentCount=students.size();
如果(!students.add(name))
抛出新的IllegalArgumentException(已添加名称+);
int newStudentCalls=studentCount==0?1//bootstrap
//已到校学生的平均人数,不少于1人
:(int)Math.round((double)callPool.size()/studentCount);
对于(int i=1;i 1){
字符串lastInPool=callPool.remove(--poolSize);
if(池索引<池大小)
callPool.set(pooldex,lastInPool);
}否则
用于(学生:学生)
如果(!student.equals(selectedStudent))
callPool.add(学生);
返回所选学生;
}
public void conductClasses(int numberOfCalls){
for(int i=0;i
我意识到这只是一个类比,但我的第一个想法是,这是一个糟糕的老师,需要不时从电脑屏幕上抬起头来,真正关注学生。。。算法。我想你已经描述了公平和循环调度算法。对于你的情况,我能想到的最好的方法是:存储所有学生的列表以及每个学生过去被调用的次数。您可以创建一个程序,从整个学生列表中随机选择一名学生,但拜访任何特定学生的可能性较小,因为他们已经被拜访了更多次。通过这种方式,所有学生(大致)被呼叫的次数相同,但不能保证任何一个学生在刚被呼叫后不久不会再次被呼叫。“随机数生成器不够好,因为少数学生可能很少被这样呼叫”据我所知,java中的
java.util.Random
和C#中的
System.Random
都可以生成均匀分布的随机数序列。你说的不会发生。@Sweeper:“你说的不会发生。”从长远来看这是正确的。但在很短的时间内,它会发生。例如,编写一个循环,使用随机数生成器生成从1到20的所有数字。您可能会惊讶地发现,有时需要50多次迭代才能生成全部20个数字。某些数字在最后一个数字生成一次之前将生成3次以上。这不满足一个学生一旦被调用,当所有其他学生都被调用时,他们可以自满的要求。这取决于您如何使用它,如果您在数组中输入所有学生3次,洗牌的数组,并开始呼吁学生按照顺序,然后没有人可以闲着。很好-这是苹果用来让音乐'洗牌'似乎更'人'随机。