生成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初始化,一般用当前日历时间初始化随机数种子,这样每行代码都可以产生不同的随机数。

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

时间: 2024-10-10 18:01:08

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

生成指定范围的一组随机数并求平均值

Math.random()是令系统随机选取大于等于 0.0 且小于 1.0 的伪随机 double 值,是Java语言常用代码. 随机数生成20~90之间的数值,并求平均数: public class Random01 { public static void main(String[] args) { int len = 5; int sum = 0; int[] arr = new int[len]; for (int i = 0; i < len; i++) { arr[i] = (int

js生成某个范围内的随机数

根据random方法,Math.random()方法返回的是0到1的随机数(不包含0和1): ? 1 2 3 4 5 6 7 8 //生成k个m到n的随机数,返回数组     function Temp(m,n,k) {         var all = new Array();         for (var i = 0; i < k; i++) {             all[i] = Math.floor(Math.random()*(n-m) + m); //Math.floor

bash的RANDOM变量生成的是真正的随机数吗

static void seedrand () { struct timeval tv; gettimeofday (&tv, NULL); sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ()); } 上述是bash中生成随机数的代码,处理是非常的简单,秒 (tv.tv_sec) 和微秒 (tv.tv_usec) 和进程 ID 的位进行异或操作来生成随机数. 由此生成的RANDOM变量是伪随机数,而且和伪随机数生成器相比,是采用非常简单的算法生成的. 译至:ht

shell生成100个6位随机数

shell生成100个6位随机数的方法很多:下面写一个,脚本如下: 执行的结果

php生成16位只有数字随机数

php生成16位只有数字随机数 分享一个php生成16位随机数的代码,php生成随机数的二种方法.方法1, <?php $a = mt_rand(10000000,99999999); $b = mt_rand(10000000,99999999); echo $a.$b; 方法2: <?php $a = range(0,9); for($i=0;$i<16;$i++){ $b[] = array_rand($a); } // www.yuju100.com var_dump(join(

js中Math.random()生成指定范围数值的随机数

http://www.111cn.net/wy/js-ajax/57062.htm Math.random() 这个方法相信大家都知道,是用来生成随机数的.不过一般的参考手册时却没有说明如何用这个方法来生成指定范围内的随机数.这次我就来详细的介绍一下Math.random(),以及如何用它来生成制定范围内的随机数.w3school的random()教程定义和用法 random() 方法可返回介于 0 ~ 1 之间的一个随机数.语法 Math.random() 返回值 0.0 ~ 1.0 之间的一

生成300个不同的随机数

--生成300个8位不重复纯数字随机数DECLARE @i INT=0;DECLARE @j INT;DECLARE @qnum INT=300; --生成随机数的数量SET NOCOUNT ONCREATE TABLE #temp_Table(num INT)WHILE(@i<@qnum)BEGIN    SELECT @j = cast( floor(rand()*(99999999-10000000)+10000000) as int)     IF(NOT EXISTS(SELECT n

生成n个不同的随机数,且随机数区间为[0,n)

生成n个不同的随机数,且随机数区间为[0,n) package cn.hgnulb.utils; import java.util.ArrayList; import java.util.List; import java.util.Random; public class TestRandom { public static void main(String[] args) { System.out.println(getDiffNO(10)); } /** * 生成n个不同的随机数,且随机数

SQL Server生成指定范围内的随机数

在开发中很多时候,我们都会遇到这种需要生成一个指定范围随机数的情况.而且在很多语言中比如Java.C#.SQl等,都会有一个函数生成一个类似于0.234273983423789的随机小数,而所有的随机数都是通过这个最基本的随机数(0.234273983423789)变化过来的. 下面我说一下生成指定范围随机数的思路,比如我要生成一个100-999范围内的随机数,我就要保证我写的生成随机数的表达式所生成的值,最大是999,最小是100.还有就是要明白一个数学里的小道理,0.99去乘一个数字所得的结