做项目的过程往往具有随机选取等过程。此笔记主要给出了随机生成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("\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)也是默认的种子。包含在库
如:
#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.
随机数产生的原理是:随机数中有一个变量种子rand,,初始会赋值给holdrand,然后用holdrand和一个公式就可以计算出新的随机数并赋值给holdrand再返回,循环产生随机数,每次得到的结果只与上次随机数的值有关,,或者你每次都通过初始化(srand((unsigned)time(0)))来改变种子进而初始化holdrand得到随机数。
三:例子(一个含有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("\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::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(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 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::iterator iter=vec_files.begin();iter!=vec_files.end();iter++)
{
out<<*iter<<"\n";
}
}
virtual bool BeginBrowse(const char *filespec)
{
string file_exts=filespec;
vector 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::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<
参考文献:
1:http://blog.chinaunix.net/uid-21228455-id-2406483.html生成k个小于n的互不相同的随机数
2:http://blog.csdn.net/kongfanyu/article/details/6387642
3:http://wenku.baidu.com/link?url=EYVSyySirpDfidGAV7beGz16gCiiNU_aZcpdtpPhL4V5y9TVVQZXWEViyb74AQvUw2lNpShtwRsxA05t0BZ3YqGxui_hvbyD5USN1pmu_m_