随机选择集合的子元素集合 -凯发k8网页登录

关注后端架构、中间件、分布式和并发编程

   :: 凯发k8网页登录首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  111 随笔 :: 10 文章 :: 2680 评论 :: 0 trackbacks
我需要一个从集合n中随机选择m个子元素的算法。 当然最好的办法是将集合打乱顺序,然后从中选择前m个元素即可。 java中现成的api可以使用:
java.util.collections.shuffle(list)
此算法非常简单,循环n次,每次长度减少1,随机获取其中一个元素,然后交换其对称元素。
public static void shuffle(list list, random rnd) {
    int size = list.size();
    if (size < shuffle_threshold || list instanceof randomaccess) {
        for (int i=size; i>1; i--)
            swap(list, i-1, rnd.nextint(i));
    } else {
        object arr[] = list.toarray();

        // shuffle array
        for (int i=size; i>1; i--)
            swap(arr, i-1, rnd.nextint(i));

        // dump array back into list
        listiterator it = list.listiterator();
        for (int i=0; i             it.next();
            it.set(arr[i]);
        }
    }
}

有点意思的swap函数

public static void swap(list list, int i, int j) {
    final list l = list;
    l.set(i, l.set(j, l.get(i)));
}

其实我们的需求很简单,在基本不变的集合中,多次重复随机获取其子集,至于子集是否有序或者随机不重要的, 重要的是原集合中的每个元素都有相似的概率出现在子集合中。

考虑到性能以及并发访问(多线程)的需要,我想到了一个简单的算法:
给定n个元素集合,从中选择m(0
  1. 随机选择索引k(0<=k
  2. 取有效元素n(k-i),n(k i) 加入未满子集m
  3. i =1, 重复(2) 直到子集m已满
  4. 终止
这样取出来的元素虽然和原始集顺序有一定的关系,但是每个元素在子集里出现的概率相当,满足结果要求。 最后生成的算法如下:
public static  list randomlist(list views, int max) {

    final int size = views.size();
    int index = randomutils.nextint(size);
    //
    list ret = new arraylist(max);
    int low = index - 1, high = index;
    while (max > 0 && (low >= 0 || high < size)) {
        if (low >= 0 && max-- > 0) {
            ret.add(views.get(low));
        }
        if (high < size && max-- > 0) {
            ret.add(views.get(high));
        }
        low--;
        high ;
    }
    return ret;
}

此算法满足如下特点:
  1. 足够快
  2. 线程安全(原始集合不变)
  3. 子元素出现概率相当(未经数学证明

另外,stackoverflow上也有一些参考链接:
  • http://mcherm.com/permalinks/1/a-random-selection-algorithm
  • http://stackoverflow.com/questions/4702036/take-n-random-elements-from-a-liste

[ 原文地址  ]


©2009-2014 imxylz
|求贤若渴
posted on 2013-08-17 17:44 imxylz 阅读(3802) 评论(3)  编辑  收藏 所属分类: j2ee技术java concurrency
# re: 随机选择集合的子元素集合 2013-08-22 16:43
如果允许改变views的话,我一般这么用
views.remove(randomutils.nextint(views.size()))
  回复  
  

# re: 随机选择集合的子元素集合 2014-06-15 23:58
真没看出来哪线程安全了。
  回复  
  

# re: 随机选择集合的子元素集合 2014-06-15 23:59
能删除吗?发错了,手机党伤不起。@梦在飞
  回复  
  


©2009-2014
网站地图