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

       做项目的过程往往具有随机选取等过程。此笔记主要给出了随机生成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初始化,一般用当前日历时间初始化随机数种子,这样每行代码都可以产生不同的随机数。还有个常量值RAND_MAX为两个字节,大小为32767.

随机数产生的原理是:随机数中有一个变量种子rand,,初始会赋值给holdrand,然后用holdrand和一个公式就可以计算出新的随机数并赋值给holdrand再返回,循环产生随机数,每次得到的结果只与上次随机数的值有关,,或者你每次都通过初始化(srand((unsigned)time(0)))来改变种子进而初始化holdrand得到随机数。


三:例子(一个含有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

3:http://wenku.baidu.com/link?url=EYVSyySirpDfidGAV7beGz16gCiiNU_aZcpdtpPhL4V5y9TVVQZXWEViyb74AQvUw2lNpShtwRsxA05t0BZ3YqGxui_hvbyD5USN1pmu_m_

猜你喜欢

转载自blog.csdn.net/Lu597203933/article/details/41850691