C实现蓄水池抽样算法

蓄水池抽样算法:
当内存无法加载全部数据时,如何从包含未知大小的数据流中随机选取k个数据(每一次读都只是K个数),并且要保证每个数据被抽取到的概率相等。
*隐含条件:*只能顺序读取,然后保证每个数读取的概率都相同,随机读取K个,也就是说内存内最多只能装下K个数据

1.当 k = 1 时
即此题的情况也就是说,我们每次只能读一个数据。
假设数据流含有N个数,我们知道如果要保证所有的数被抽到的概率相等,那么每个数抽到的概率应该为 1/N
那如何保证呢?

先说方案:

每次只保留一个数,当遇到第 i 个数时,以 1/i的概率保留它,(i-1)/i的概率保留原来的数。
举例说明: 1 - 10

遇到1,概率为1,保留第一个数。
遇到2,概率为1/2,这个时候,1和2各1/2的概率被保留
遇到3,3被保留的概率为1/3,(之前剩下的数假设1被保留),2/3的概率 1 被保留,(此时1被保留的总概率为 2/3 * 1/2 = 1/3)
遇到4,4被保留的概率为1/4,(之前剩下的数假设1被保留),3/4的概率 1 被保留,(此时1被保留的总概率为 3/4 * 2/3 * 1/2 = 1/4

以此类推,每个数被保留的概率都是1/N。

2.当K=m (m>1)
对任意N个数,抽取K个数,每一个数被抽到的概率都是 K N \frac{K}{N} NK
假设内存最大为K,当前K 个数据时候,每一个都会被保留,概率为1,当第K+1个到来时候,抽到这个数的概率是 K K + 1 \frac{K}{K+1} K+1K*,那么在前K个数中任意一个数保留下来的概率是
p=(未抽到第k+1) * (前K个中选k个) +(抽到第k+1) * (前K个中选k-1个)
如下:在这里插入图片描述同理对第K+2个同样成立,
假设第 i 个数据到来,前 i-1个数抽K个每一个抽中的概率是 K i − 1 \frac{K}{i-1} i1K

p=(未抽到第 i ) * (前 i-1个中选k个) +(抽到第 i ) * (前 i-1 个中选k-1个)
代码实现:

相关题目:
给定一个单链表,随机选择链表的一个节点,并返回相应的节点值。保证每个节点被选的概率一样。

进阶:
如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现?

示例:

// 初始化一个单链表 [1,2,3].
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
Solution solution = new Solution(head);

// getRandom()方法应随机返回1,2,3中的一个,保证每个元素被返回的概率相等。
solution.getRandom();

题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-random-node

//蓄水池抽样法。使用rand函数来进行实现。
/*rand产生一个0-0x7fff的随机数,即最大是32767的一个数
如果想要表示一个数是从0开始到最大值的,比如说,想要产生一个0-99之间的随机数,那么用法如下
int num = rand() % 100;
如果想要产生一个数是从1开始到最大值的,比如说,想要产生一个1-100之间的随机数,那么用法如下
int num = rand() % 100 + 1;
*/


typedef struct {
    
    
    struct ListNode* head;
} Solution;

/** @param head The linked list's head.
        Note that the head is guaranteed to be not null, so it contains at least one node. */

Solution* solutionCreate(struct ListNode* head) {
    
    
    Solution* solution = (Solution*) malloc(sizeof(Solution));
    solution->head = head;
    return solution;
}

/** Returns a random node's value. */
int solutionGetRandom(Solution* obj) {
    
    
  struct ListNode* temp = obj->head;
  int res = 0;
  int count = 0;
  int randNum = 0;
  while(temp) {
    
    
      if(0 == count++) {
    
    
          res = temp->val;
      }
      else {
    
    
          randNum = rand() % count;
          if(randNum < 1) {
    
    
              res = temp->val;
          }
      }
      temp = temp->next;
  }
  return res;
}

void solutionFree(Solution* obj) {
    
    
    free(obj);
    obj = NULL;
}

猜你喜欢

转载自blog.csdn.net/weixin_44910502/article/details/114312606
今日推荐