zoukankan      html  css  js  c++  java
  • 前N个自然数的随机置换

    来自:【数据结构与算法分析——C语言描述】练习2.7

    问题描述:假设需要生成前N个自然数的一个随机置换。例如,{4,1,2,5,2} 和 {3,1,4,2,5} 就是合法的置换,但 {5,4,1,2,1} 却不是,因为数1出现了两次而数 3 缺没有。这个程序常常用于模拟一些算法。我们假设存在一个随机数生成器 randInt(i, j) ,它以相同的概率生成 i 和 j 之间的一个整数。

    下面是三个算法:

    1.如下填入 A[0] 到 A[N-1] 的数组 A;为了填入 A[i] ,生成随机数直到它不同于已经生成的 A[0], A[1],  ... ,  A[i-1] 时,再将其填入 A[i] 。

    2.同算法1,但是要保存一个附加的数组,称之为 Used(用过的)数组。当一个随机数 Ran 最初被放入数组A的时候,置Used[Ran]=1。这就是说,当用一个随机数填入 A[i] 时,可以用一步来测试是否该随机数已经被使用,而不是像第一个算法那样(可能)进行 i 步测试。

    3.填写该数组使得 A[i] = i + 1。然后

    for(i = 1; i < N; i++) 
        swap(&A[i], &A[randInt(0, i)]);

    题目中有说“我们假设存在一个随机数RandInt(i, j)”,既然如此,暂时不必考虑其内部实现以及内存限制,只根据这个接口考虑算法即可。

    算法1

    i = 0;
    while (i < N)
    {
        ran = randInt(0, N);
        for (k = 0; k < i; k++)
        {
            if (A[k] == ran)
                break;
        }
        if (k == i)
        {
            A[i] = ran;
            count++;
        }
    }

    以循环次数作为时间度量。循环从i=0到i=n-1写出n个不重复随机数,因为生成第i个不重复随机数的概率是(N-i)/N,所以理论上经过N/(N-i)次生成,得到不重复随机数的概率为1。所以总耗时为

    这里做了分子的放大,以及这个调和和公式:

    该算法的时间复杂度即为O(N2logN)。

    算法2

    i = 0;
    while (i < N)
    {
        ran = randInt(0, N);
        if (used[ran] == 0)
        {
            A[i] = ran;
            used[ran] = 1;
            i++;
        }
    }

    算法 2 比算法 1 少了内层的 for 循环,所以时间复杂度降了一阶,即为 O(NlogN)。

    算法3

    for (i = 0; i < N; i++)
        A[i] = i + 1;
    for (i = 0; i < N; i++)
        swap(&A[i], &A[randInt(0, i)]);

    时间复杂度显然是线性级的,O(N)。

  • 相关阅读:
    #ASP.NET Core 1.0 Key Features
    #asp.net core mvc 的视图注入
    # asp.net core 1.0 项目结构
    dotnet core 初试两个小问题解决
    1044 火星数字(20 分)
    1043 输出PATest(20 分)
    1042 字符统计(20 分)
    1041 考试座位号(15 分)
    1040 有几个PAT(25 分)
    1039 到底买不买(20 分)
  • 原文地址:https://www.cnblogs.com/mingc/p/5879733.html
Copyright © 2011-2022 走看看