【问题标题】:Selecting a random node from a list in C从C中的列表中选择一个随机节点
【发布时间】:2017-10-02 09:00:39
【问题描述】:

我有一个列表,我想从中随机选择一个节点。因为它不是一个数组,所以我事先不知道它的长度。有没有办法随机选择一个节点(均匀分布)不必扫描整个列表(在最坏的情况下)两次(即获取它的长度并随机选择位置后到达所选节点)?

这是我用于列表的代码:

struct mynode {
    in_addr_t paddr;
    struct mynode *prev, *next;
};

struct mylist {
    struct mynode *first, *last;
    char *name;
};

【问题讨论】:

  • 简单的方法:维护一个计数器,同时添加一个(ny)节点,更新它。
  • Reservoir search(又名 Knuth 的算法 R,虽然它不是 Knuth 发明的)但是您仍然必须使其适应您的列表或树。它只需要对整个结构进行一次扫描。
  • 糟糕,不是搜索,而是采样 GIYF
  • 这听起来很矛盾;如果随机过程决定了“最后一个元素”,那么如果不遍历整个列表就无法到达那里。如果它因此“不能”选择那个,那么选择不是同质的,对吧?我认为水库搜索的存在就是答案,这就是你需要做的。

标签: c list random


【解决方案1】:

按照 joopIlja Everilä 在 cmets 中的建议,我在 C 中实现了 reservoir sampling

struct mynode *select_mynode(struct mylist *list) {
    struct mynode *list_iter = list->first; // An iterator to scan the list
    struct mynode *sel_node = list_iter; // The node that will be selected
    int count = 2; // Temporary size of the list
    srand((unsigned int) time(NULL)); // Seed
    // Select a random element in O(n)
    while (list_iter->next != NULL) {
        if (rand() % count == (count - 1))
            sel_node = list_iter->next;
        list_iter = list_iter->next;
        count++;
    }
    return sel_node;
}

注意:有关随机选择的更多信息,请参阅here

【讨论】:

  • 就是这样。次要挑剔:if (rand() % count == (count - 1)) 不是无偏统一随机的。
  • 再次感谢您的提示!我只是在答案中添加了注释。我认为编辑代码会降低可读性
  • 考虑到rand 通常是多么的残暴,抱怨模数中坦率的微不足道的偏见是错误的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-11
  • 1970-01-01
  • 2012-09-11
  • 1970-01-01
  • 2012-09-11
相关资源
最近更新 更多