在给定范围中取不重复的随机数

在给定范围中取不重复的随机数

    随机取m个数(在1n的范围之内),(m<=n),要求m个数没有重复。有没有什么好的算法,时间复杂度和空间复杂度都很好

方法一:STL中的set集,红黑树来处理

取随机数可以用C++标准的rand,至于M个不重复,用std::set来解决,把取的随机数插入到set里面,通过setsize()==m来判断是否已取够m个了。

#include <set>

#include <stdlib.h>

int main()

{

std::set<int> s;

while(1)

 {

  int r = rand()%n;

  s.insert(r);

  if(s.size() == m)

  {

   break;

  }//if

 }//while

}


 

由于set底层实现是红黑树,插入复杂度是对数级

:

#include <iostream>

#include <cstdlib>      //用于rand()和srand()函数

#include <ctime>        //设置不同的随机数

using namespace std;

int main (){

srand( time( 0 ) );    //调用不重复的随机数函数

unsigned i;

for ( int n = 0; n++ < 10; )

{

i = rand() ;        //对i 赋系统的随机数

cout << " The NO." << n << "is : " << i << endl;

}

return 0;

}


 

1 C++标准函数库提供一随机数生成器rand,返回0RAND_MAX之间均匀分布的伪随机整数。 RAND_MAX必须至少为32767rand()函数不接受参数,默认以1为种子(即起始值)。随机数生成器总是以相同的种子开始,所以形成的伪随机数列也相同。失去了随机意义。

2C++中另一函数srand(),可以指定不同的数(无符号整数变元)为种子。但是如果种子相同,伪随机数列也相同。

3比较理想的是用变化的数,比如时间来作为随机数生成器的种子。

在头文件ctime中时间库包含time函数,它可以返回一个表示时间、日期、月和年的数值使用如下调用可将该值设为rand的种子

srand(static_cast<unsigned>(time(static_cast<time_t*>(NULL))));

4. srand()并不是说使随机数都不一样,它只是使取随机数的种子随着时间而改变

方法三:以下方法需要附加空间b数组,我们还是假设100个数据。

(1)将范围数组b[100](b[i]=100+i,不妨设数组下标从1开始)的每个元素设置一个标志位flag初始均为flag=0;若某元素被选入到a数组中,flag=1;显然,以后再选到重复元素可以立刻判定是否已选但是仍然有一个很严重的问题,在小规模输入下,无疑它的表现是不错的但现在举一个失败的例子.

1~65536之间,选择65500个不重复的随机数看看后面的随机数,比如第65500个数(最后一个),它要在剩下的36个数中选择才会有flag=0(根本不知道这36个数是什么)

改进:先在1~65536之间随机选取36个数,删除.将剩下的65500个数依次赋值给a[65500],然后打乱顺序即可

当范围数组与目标数组的大小非常接近时,上述算法非常有效,建议采用

(2)问题的最终解决.

仍以最开始的那个例子来说,初始数组b[i]=100+i,a数组空。(a是我们需要的存放生成的随即数的数组,我们需要从b数组中取数

每次随机生成数组b的一个下标subscript,然后取出它所对应的数据b[subscript],记下来a当前的存储单位a[j]然后将数组b的最后一个数b[length]覆盖b[subscript]的位置,同时将数组a指向下一个数,b数组的长度减1。尽管前若干次生成的下标subscript随机数有可能相同,但因为每一次都把最后一个数填到取出的位置,因此,相同下标subscript对应的数却绝不会相同,每一次取出的数都不会一样,这样,就保证了算法的确定性、有效性、有穷性

参考:

1、百度博客文章,源地址丢失,谢谢原作者


转:http://blog.163.com/zhoumhan_0351/blog/static/399542272010327104318489/
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值