如何高效的从大量关键字中选择N个不同的关键字

问题描述:

假设有Sum=10亿个关键字,以文件形式存储,一行一个关键字。

其中有重复的。共大约有K=1亿个不同关键字。

现在要求从这里  随机选取 N个不同的关键字。

注意:随机选取要考虑 关键字的频数

     N可能很小也可能很大

请设计一个 尽量高效的算法

------------------------------------------------------------------------

当前思路:

N如果较小,就按一般方式处理

N如果较大,可能需要判断 当前选择的关键字是否已经被选择,如果被选择过了,则需重选。这个过程的复杂度 太大

所以要尽量避免,选择到重复的关键字。 直接思路是每次选择 一个关键字后 就将其从被选 关键字集里剔除。但这里必须保证每个关键字被选中的概率不变。

比如 有如下关键字和对应频数

A 2

B 1

C 1

D 1

在从这里选择两个关键字的前提下,A被选中的概率是:2/5*1+3/5*2/4=21/30 以此类推

如果每个关键字只出现一次的话,就相对容易些,维持一个线性表,在逻辑上将这个线性表看成两部分,

前面部分是待选关键字集,后面是已选关键字集。每次随机选择一个关键字后,就把它和后面的数据交换一下。更改rand范围即可。

但是这里每个关键字出现的次数是不一样的。rand的设计不再那么简单

总体上有那么几个想法

1.保留重复判断

1.1利用折半查找进行快速定位与判断

对已选择的关键字集进行折半插入排序,每次选择了一个关键字后,用折半查找进行定位与判断。

折半插入排序代价是O(N2),每次插入一个新的关键字

折半查找代价是O(logN)。所以时间复杂度是O(N2)

空间复杂度O(N)

1.2利用hash进行快速判断

有点类似与数据库cache中,页面是否已在cache里的判断。引入hash,链表等。

假设hash使用mod(N)实现

空间复杂度是O(N)

时间复杂度是O(N)

1.3保留重复判断的一个重要问题

保留重复判断有一个非常严重的问题,假设N逼近关键字种类数。

越到后面,随机选择到新的关键字的概率越小,需要重复随机选择的次数越多。

故上述方法一般适用N<<K的情况。当N->K/2时,考虑取消重复判断,即需要构造随机选择

2.取消重复判断

难点在于随机选择的构造,也许这个构造本身的代价也是很大的。

我想了很久,要即可行效率又不能比前面的差。

我的想法是先计算出每个关键字被选到的概率。

还是前面的例子A 21/30 B 1/10 C 1/10 D 1/10

rand=rand(0,sum)sum初始为1

然后麻烦的就是建立rand和i(关键字序号)之间的关系,这个查找过程消耗的代价也很大。

因为每次选完一个后,都要剔除,所以使用累计概率是不妥的。只能一个个比对过去,边计算累计概率,边比对。

概率的计算复杂度目前还没数

后面选择的复杂度应该是O(N)的。

原文地址:https://www.cnblogs.com/2010Freeze/p/2557310.html