生成N个不同的随机数(C++,范围0~N-1)(一)

2015-01-24 09:22:13 · 作者: · 浏览: 8

做项目的过程往往具有随机选取等过程。此笔记主要给出了随机生成N个不同的随机数的两种方法,然后简单的介绍了C++中随机数主要用到的函数srand,rand和time。最后给出了一个简单的例子,即从一个含有N张图片的文件夹中随机选取K张图片存入另外一个文件夹。

一:产生N个不同随机数的方法

?

#include 
  
   
#include 
   
     #include
    
      #define N 20 #define K 10 void swap(int *a, int *b) { if(*a != *b){ // 异或操作 交换两个数字的位置 *a ^= *b; *b ^= *a; *a ^= *b; } } /****************************************************************************** *函数名称:void generateDiffRandV1(int a[], int n) *函数功能:产生互不相同的随机数 *入口参数: *返 回 值:无 *备 注:以空间换时间 *******************************************************************************/ void generateDiffRandV1(int a[], int n, int k) { int i; time_t t; for (i = 0; i < n; i++){ a[i] = i; } srand((int)time(&t)); for (i = 0; i < k; i++){ swap(&a[i], &a[i+rand()%(n-i)]); } } /****************************************************************************** *函数名称:void generateDiffRandV2(int a[], int n) *函数功能:产生互不相同的随机数(产生随机数的范围是1~n-1) *入口参数: *返 回 值:无 * *思 路:先生成一个放置座号的数组,然后从中随机抽取,抽取后为防止重复,立即归零。 * :每次生成座号,只需判断是否为0 即可,大大提高了程序执行的效率。 *******************************************************************************/ void generateDiffRandV2(int a[], int n) { int *flag =(int *)malloc(sizeof(int) * n); static int flag_once = 0; int i, index; for(i = 0; i < n; i++) flag[i] = i+1; if(!flag_once){ srand(time(0)); flag_once = 1; } for(i = 0; i < n;){ index = rand() % n; if(flag[index] != 0){ a[i++] = flag[index]-1; flag[index] = 0; } } free(flag); } void printArray(int a[], int n) { int i; for (i = 0; i < n; i++){ printf(%d , a[i]); } printf( ); } int main() { int a[N]; generateDiffRandV1(a, N, K); printArray(a, N); generateDiffRandV2(a, N); printArray(a, N); return 0; }
    
   
  

?

\

二:srand,rand及time函数的简介

1:srand函数是随机数发生器的初始化函数。它需要提供一个种子,这个种子会对应一个随机数,如果使用相同的种子,后面的rand() 函数会出现一样的随机数。如:srand(1); 直接使用1来初始化种子,srand(1)也是默认的种子。包含在库 中。

如:

?

#include 
  
   
#include 
   
     using namespace std; int main(){ // srand 相当于随机数的初始化函数,为随机数播下种子, //srand((unsigned)time(0)); // time返回的是time_t类型 srand(1); //time_t t= time(0); for(int i = 0; i < 10; i++) { cout << rand() << endl; } return 0; }
   
  
\

?

不管这段代码运行多少次,它始终是从种子1开始产生随机数,所以结果都是一样的。

为了避免这种情况,我们使用了srand((unsigned)time(0)); 0代表NULL,time(NULL)是获得当前时间的意思,这样每次运行就都能产生不同的随机数了。time()返回的结果为time_t,强制转换为了unsigned类型,包含在库 中。

2:rand函数为伪随机数发生器,需要先调用srand初始化,一般用当前日历时间初始化随机数种子,这样每行代码都可以产生不同的随机数。还有个常量值RAND_MAX为两个字节,大小为32767.

?

三:例子(一个含有N张图片的文件夹中随机选取K张图片存入另外一个文件夹)

?

/*
从图库中随机选择1w张各不相同的图片
*/
#include 
  
   
#include 
   
     // 用到了srand函数,所以用到了这个头文件 #include 
    
      #include BrowseDir.hpp #include 
     
       #include 
      
        #include 
       
         #include
        
          // 用到了time函数,所以要用到这个头文件 using namespace std; #define N 20000 // 需要修改 总共数量 // 随机产生n个不同的随机数 并保存在a数组中 void generateDiffRandV2(int a[], int n) { int *flag =(int *)malloc(sizeof(int) * n); static int flag_once = 0; int i, index; for(i = 0; i < n; i++) flag[i] = i+1; if(!flag_once){ srand(time(0)); //0 代表NULL, time(NULL)是获得当前时间的意思 没有这句每次产生的随机数和上次是一样的 flag_once = 1; } for(i = 0; i < n;){ index = rand() % n; if(flag[index] != 0){ a[i++] = flag[index]-1; flag[index] = 0; } } free(flag); } void printArray(int a[], int n) { int i; for (i = 0; i < n; i++){ printf(%d , a[i]); } printf( ); } void imgProcessing(const char* dir_path, const char* file_exts, int a[],int selectNum) { CStatDir stat_dir; stat_dir.SetInitDir(dir_path); stat_dir.BeginBrowse(file_exts); int indx=0; sort(a, a+selectNum); // 排序函数 //printArray(a, selectNum); int i =0, j=0; int count=0; // 统计出错图片个数 for (vector
         
          ::iterator iter=stat_dir.vec_files.begin();iter!=stat_dir.vec_files.end() && j < selectNum;iter++) { if(i==a[j]){ // 得到图片保存路径 string img_file = *iter; string pre_img_save = img_file.substr(0,img_file.find_last_of(\))+_1w; string img_save = pre_img_save+img_file.substr(img_file.find_last_of(\)); IplImage* img= cvLoadImage((*iter).c_str(),1); if(!img) { cout << fail to load image << endl; count ++; } else{ cout << a[j] << endl; cvSaveImage(img_save.c_str(), img); } j++; i++; cvReleaseImage(&img); } else i++; } cout << the error img: << count << endl; } int main() { int a[N]; generateDiffRandV2(a, N); // printArray(a, 50); const char *img_dir = E:\wang\data\图片; // 图片路劲 需要改动 const char *file_exts=*.jpg|*.png; int selectNum = 10000; // 选择图片数量 需要改动 imgProcessing(img_dir, file_exts, a, selectNum); return 0; }
         
        
       
      
     
    
   
  

?

目录操作代码BrowseDir.hpp:

?

#pragma once
#include 
  
   
#include 
   
     #include 
    
      #include 
     
       #include 
      
        #include 
       
         #include 
        
          #include 
         
           #include 
          
            using namespace std; class CBrowseDir { protected: //存放初始目录的绝对路径,以''结尾 char m_szInitDir[_MAX_PATH]; public: //缺省构造器 CBrowseDir(); //设置初始目录为dir,如果返回false,表示目录不可用 bool SetInitDir(const char *dir); //开始遍历初始目录及其子目录下由filespec指定类型的文件 //filespec可以使用通配符 * ?,不能包含路径。 //如果返回false,表示遍历过程被用户中止 virtual bool BeginBrowse(const char *filespec); protected: //遍历目录dir下由filespec指定的文件 //对于子目录,采用迭代的方法 //如果返回false,表示中止遍历文件 bool BrowseDir(const char *dir,const char *filespec); //函数BrowseDir每找到一个文件,就调用ProcessFile //并把文件名作为参数传递过去 //如果返回false,表示中止遍历文件 //用户可以覆写该函数,加入自己的处理代码 virtual bool ProcessFile(const char *filename); //函数BrowseDir每进入一个目录,就调用ProcessDir //并把正在处理的目录名及上一级目录名作为参数传递过去 //如果正在处理的是初始目录,则parentdir=NULL //用户可以覆写该函数,加入自己的处理代码 //比如用户可以在这里统计子目录的个数 virtual void ProcessDir(const char *currentdir,const char *parentdir); }; CBrowseDir::CBrowseDir() { //用当前目录初始化m_szInitDir getcwd(m_szInitDir,_MAX_PATH); //如果目录的最后一个字母不是'',则在最后加上一个'' int len=strlen(m_szInitDir); if (m_szInitDir[len-1] != '\') strcat(m_szInitDir,\); } bool CBrowseDir::SetInitDir(const char *dir) { //先把dir转换为绝对路径 if (_fullpath(m_szInitDir,dir,_MAX_PATH) == NULL) return false; //判断目录是否存在 if (_chdir(m_szInitDir) != 0) return false; //如果目录的最后一个字母不是'',则在最后加上一个'' int len=strlen(m_szInitDir); if (m_szInitDir[len-1] != '\') strcat(m_szInitDir,\); return true; } bool CBrowseDir::BeginBrowse(