蓄水池抽样算法

什么是蓄水池抽样,它能解决什么问题?html

从一次面试提及

百度面试以算法为主啊,手动写代码。第一道题是实现c语言库函数strcpy,这个原理很简单,但要注意如下这几点:java

  • 空指针检查(包括src和dest)
  • 内存重叠,要检查指针是否重叠
  • 最后拷贝时,别忘了在dest追加字符串终结符号0
  • 如何保证dest已分配足够内存
  • 为何从后往前拷贝?

第二道题是写一个java类,实现堆的操做。说实话,虽然堆的操做不难,但要真正实现它并不容易。如下须要注意的点:python

  • 泛型参数(泛化编程)
  • 类型必需可比较或者提供比较器
  • 不能实例泛型类型,即不能new T[]或者new T(),只能使用Object数组
  • 内存动态分配,内存拷贝(数组拷贝)

重点是第三道题目:给定一个文件,从中随机取出n行,并计算时间复杂度。我上来即是这样的代码:面试

import random
def sample(filename, n = 3):
    assert(filename is not None)
    result = []
    with open(filename) as f:
        lines = f.readlines()
    while len(result) < n :
        line = random.choice(lines)
        if line not in result:
            result.append(line.strip())
    return result

这种方法算法

  • 必须把文件内容全读入内存,若是文件很大怎么办?
  • 设N为文件行数,n和N接近时,越到后面,冲突越大,效率极低。
  • 有人说,先随机生成n个数构成一个集合A(仍是有冲突哦),读取文件,当行数属于A时,取出该行,问题不就解决了?
    问题是文件总行数是多少?必须知道文件总行数才能知道随机数的取值范围啊。必须先扫描一遍文件?文件很大时这样的效率如何?

后来面试官问我知不知道分治法,我说了解,但这有关系么?编程

蓄水池抽样

蓄水池抽样(Reservoir Sampling )是一个颇有趣的问题,它可以在o(n)时间内对n个数据进行等几率随机抽取,
例如:从1000个数据中等几率随机抽取出100个。另外,若是数据集合的量特别大或者还在增加(至关于未知数据集合总量),
该算法依然能够等几率抽样。数组

以上摘自handspeaker博客app

算法步骤为:dom

  1. 从文件中取前n行,结果集result
  2. 令i表示当前行数,c为当前行内容,m = random(1, i),即m为1~i的一个随机数。
  3. 若m <= n, 则令result[m] = c,即替换第m行内容,不然舍弃c。
  4. 若已到文件结尾,退出算法,返回result,不然转2

利用概括法能够证实每行被取的几率是相等的,证实过程
handspeaker博客函数

回到问题

问题解决了,毫无悬念!

import random
def sample(filename, n = 5):
    assert(filename is not None)
    result = []
    with open(filename, mode = "r") as f:
        for i in range(n):
            line = f.readline()
            if line == '':
                return result
            else:
                result.append(line.strip())
        i = n
        for line in f:
            k = random.randint(0, i)
            if k < n:
                result[k] = line.strip()
            i += 1
    return result
相关文章
相关标签/搜索