📜  选择带权重的随机数 - C 编程语言(1)

📅  最后修改于: 2023-12-03 15:12:21.759000             🧑  作者: Mango

选择带权重的随机数 - C 编程语言

在编程过程中, 我们常常需要从一些带权重的数据中进行随机选择。比如, 在游戏中, 我们需要从一定概率分布下生成不同的NPC或怪物;在推荐系统中, 我们需要从物品库中选出一些物品进行推荐等。

本文将介绍一些实现方法,帮助程序员实现这些随机选择过程。

使用概率分布随机数

在 C 语言中,可以使用rand()函数生成一个随机数,默认生成的随机数会均匀分布在 0 ~ RAND_MAX 之间。如果我们需要生成一定概率分布下的随机数,可以通过修改这个随机数的生成范围及使用权重来实现。

下面是一个示例代码,主要是通过使用概率分布来实现带权重的随机数选择:

#include <stdlib.h>

int weighted_random(int* weights, int size) {
    int total_weight = 0, selected_index = 0;

    // 计算所有权重之和
    for (int i = 0; i < size; i++) {
        total_weight += weights[i];
    }

    // 根据权重主键选择随机数
    int random_weight = rand() % total_weight;
    for(int i = 0; i < size; i++) {
        selected_index = i;
        if (random_weight < weights[i]) {
            break;
        }
        random_weight -= weights[i];
    }

    return selected_index;
}

int main() {
    int weights[] = {1, 2, 3, 4, 5};
    int size = sizeof(weights) / sizeof(weights[0]);

    for (int i = 0; i < 10; i++) {
        int random_index = weighted_random(weights, size);
        printf("Select item #%d with weight %d\n", random_index, weights[random_index]);
    }

    return 0;
}

代码中,我们首先计算所有权重的之和,然后随机生成一定范围内的随机数,并根据该随机数从前往后遍历每个权重值,累加它们的权重值,直到累加的权重值超过了随机数。此时,即可选出一个随机项,其在权重分布中的位置即为所选的位置。

使用轮盘赌算法

上述方法并不高效,而且当权重极端不均衡时,可能导致某些项被选中的概率过低。更好的选择是使用轮盘赌算法,将选定随机数与累加权重值与整个权重和的比值进行比较,以此为标准来选择元素。

下面是一个示例代码,主要是通过使用轮盘赌算法来实现带权重的随机数选择:

#include <stdlib.h>
#include <math.h>

int roulette_random(double* weights, int size) {
    double total_weight = 0.0, selected_weight = 0.0;

    // 计算所有权重之和
    for (int i = 0; i < size; i++) {
        total_weight += weights[i];
    }

    // 使用轮盘赌算法选择随机数
    double random_weight = (double)rand() / RAND_MAX;
    for(int i = 0; i < size; i++) {
        selected_weight += weights[i] / total_weight;
        if (random_weight < selected_weight) {
            return i;
        }
    }

    return size - 1;
}

int main() {
    double weights[] = {1.0, 2.0, 3.0, 4.0, 5.0};
    int size = sizeof(weights) / sizeof(weights[0]);

    for (int i = 0; i < 10; i++) {
        int random_index = roulette_random(weights, size);
        printf("Select item #%d with weight %lf\n", random_index, weights[random_index]);
    }

    return 0;
}

代码中,我们首先计算所有权重的之和,然后随机生成一个浮点数,并以此作为轮盘上的指针。接着遍历每个权重,对于每个权重,累加它们的权重值/总权重值的比值,直到累加的权重值比指针值大,此时,即可选出对应的随机项。

到此,我们就完成了利用某个概率分布生成随机数的过程。

总结

带权重的随机选择可以使用不同的方法实现,比如,可以使用概率分布来实现,也可以使用轮盘赌算法来实现。不同的方法适用于不同的场景,程序员可以根据实际情况选择合适的方法来完成带权重的随机选择。