做项目的过程往往具有随机选取等过程。此笔记主要给出了随机生成N个不同的随机数的两种方法,然后简单的介绍了C++中随机数主要用到的函数srand,rand和time。最后给出了一个简单的例子,即从一个含有N张图片的文件夹中随机选取K张图片存入另外一个文件夹。
一:产生N个不同随机数的方法
#include <stdio.h> #include <stdlib.h> #include<time.h> #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("\n"); } 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)也是默认的种子。包含在库<stdlib.h>中。
如:
#include <iostream> #include <time.h> 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类型,包含在库<time.h>中。
2:rand函数为伪随机数发生器,需要先调用srand初始化,一般用当前日历时间初始化随机数种子,这样每行代码都可以产生不同的随机数。
三:例子(一个含有N张图片的文件夹中随机选取K张图片存入另外一个文件夹)
/* 从图库中随机选择1w张各不相同的图片 */ #include <stdio.h> #include <stdlib.h> // 用到了srand函数,所以用到了这个头文件 #include <iostream> #include "BrowseDir.hpp" #include <cv.h> #include <highgui.h> #include <algorithm> #include<time.h> // 用到了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("\n"); } 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<string>::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 <stdio.h> #include <stdlib.h> #include <direct.h> #include <string.h> #include <iostream> #include <io.h> #include <vector> #include <fstream> #include <string> 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(const char *filespec) { ProcessDir(m_szInitDir,NULL); return BrowseDir(m_szInitDir,filespec); } bool CBrowseDir::BrowseDir(const char *dir,const char *filespec) { _chdir(dir); //首先查找dir中符合要求的文件 long hFile; _finddata_t fileinfo; if ((hFile=_findfirst(filespec,&fileinfo)) != -1) { do { //检查是不是目录 //如果不是,则进行处理 if (!(fileinfo.attrib & _A_SUBDIR)) { char filename[_MAX_PATH]; strcpy(filename,dir); strcat(filename,fileinfo.name); //cout << filename << endl; if (!ProcessFile(filename)) return false; } } while (_findnext(hFile,&fileinfo) == 0); _findclose(hFile); } //查找dir中的子目录 //因为在处理dir中的文件时,派生类的ProcessFile有可能改变了 //当前目录,因此还要重新设置当前目录为dir。 //执行过_findfirst后,可能系统记录下了相关信息,因此改变目录 //对_findnext没有影响。 _chdir(dir); if ((hFile=_findfirst("*.*",&fileinfo)) != -1) { do { //检查是不是目录 //如果是,再检查是不是 . 或 .. //如果不是,进行迭代 if ((fileinfo.attrib & _A_SUBDIR)) { if (strcmp(fileinfo.name,".") != 0 && strcmp (fileinfo.name,"..") != 0) { char subdir[_MAX_PATH]; strcpy(subdir,dir); strcat(subdir,fileinfo.name); strcat(subdir,"\\"); ProcessDir(subdir,dir); if (!BrowseDir(subdir,filespec)) return false; } } } while (_findnext(hFile,&fileinfo) == 0); _findclose(hFile); } return true; } bool CBrowseDir::ProcessFile(const char *filename) { return true; } void CBrowseDir::ProcessDir(const char *currentdir,const char *parentdir) { } //从CBrowseDir派生出的子类,用来统计目录中的文件及子目录个数 class CStatDir:public CBrowseDir { protected: int m_nFileCount; //保存文件个数 int m_nSubdirCount; //保存子目录个数 public: vector<string> vec_files; public: //缺省构造器 CStatDir() { //初始化数据成员m_nFileCount和m_nSubdirCount m_nFileCount=m_nSubdirCount=0; } //返回文件个数 int GetFileCount() { return m_nFileCount; } //返回子目录个数 int GetSubdirCount() { //因为进入初始目录时,也会调用函数ProcessDir, //所以减1后才是真正的子目录个数。 return m_nSubdirCount-1; } void VisitedFiles(ostream&out) { for (vector<string>::iterator iter=vec_files.begin();iter!=vec_files.end();iter++) { out<<*iter<<"\n"; } } virtual bool BeginBrowse(const char *filespec) { string file_exts=filespec; vector<string> vec_exts; size_t pos_start=0; size_t npos=file_exts.find("|"); string exts; while(npos!=string::npos) { exts=file_exts.substr(pos_start,npos-pos_start); vec_exts.push_back(exts); pos_start=npos+1; npos=file_exts.find("|",pos_start); } exts=file_exts.substr(pos_start); vec_exts.push_back(exts); bool sign=true; for (vector<string>::iterator iter=vec_exts.begin();iter!=vec_exts.end();iter++) { exts=*iter; if (!CBrowseDir::BeginBrowse(exts.c_str())) { sign=false; } } return sign; } protected: //覆写虚函数ProcessFile,每调用一次,文件个数加1 virtual bool ProcessFile(const char *filename) { m_nFileCount++; //cout<<filename<<endl; vec_files.push_back(filename); return CBrowseDir::ProcessFile(filename); } //覆写虚函数ProcessDir,每调用一次,子目录个数加1 virtual void ProcessDir (const char *currentdir,const char *parentdir) { m_nSubdirCount++; CBrowseDir::ProcessDir(currentdir,parentdir); } };
参考文献:
1:http://blog.chinaunix.net/uid-21228455-id-2406483.html生成k个小于n的互不相同的随机数
2:http://blog.csdn.net/kongfanyu/article/details/6387642
原文地址:http://blog.csdn.net/lu597203933/article/details/41850691