Java 随机数之从指定数据范围内随机选取n个不重复的数据

                   Java 随机数之从指定数据范围内随机选取n个不重复的数据

一、简述

       记--从指定数据范围内随机选取n个不重复的数据,如从1~100中随机选取10个数据。

二、效果

 

三、工程结构

四、源文件

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.lang.Integer;

public class RandomTest {
	static List<Integer> mBaseList = null;
	
	//从[minVal, topVal]范围中选出cnt个不重复的数据
	public static List<Integer> genUniqueRandomVal(int minVal, int topVal, int cnt){
        int index;
        int size = topVal-minVal+1;
        if (minVal >= topVal){
            return null;
        }
        
        if (cnt>size){
            return null;
        }

        if (null == mBaseList){
            mBaseList = new ArrayList<Integer>();
        }

        //初始化基本数据集合
        mBaseList.clear();
        for (int i = minVal; i <= topVal; i++){
            mBaseList.add(i);
        }
        
        List<Integer> uniqueValList = new ArrayList<Integer>();//无重复的数据集合
        Random random = new Random();
        for (; cnt > 0;){
            index = random.nextInt(size);//范围[0, size)
            uniqueValList.add(mBaseList.get(index));//添加到数据集合
            mBaseList.remove(index);//基本数据集合移除已经加到uniqueValList的数据,这样子就不会重复
            cnt--;
            size--;
        }
        return uniqueValList;
    }
	
	public static void main(String[] args) {
		System.out.println("Please input min,max,count:");
		Scanner scan = new Scanner(System.in);
		
		//从输入流中获取三个数值
		int min = Integer.parseInt(scan.next());
		int max = 0;
		int cnt = 0;
		if(scan.hasNext()){
			max = Integer.parseInt(scan.next());
			if(scan.hasNext()){
				cnt = Integer.parseInt(scan.next());
				List<Integer> list = RandomTest.genUniqueRandomVal(min, max, cnt);
				for(Integer i : list) {//遍历打印得到的数据集合
					System.out.print(i+" ");
				}
			}
		}
		System.out.println("\nFinish.");
	}

}

五、分析

          指定范围内的随机数是会有重复的可能,并且小范围多次随机时重复率很高,为了快速生成不重复的随机数,我们需要保证每次得到的随机数是不一样的。如果生成的随机数是重复的,那么再生成一次,直到不重复。这个方法是不可取的,当选取数很接近数据总数时候,重复率是非常大的,如1~100中随机选取99不同的数时,可能需要生成次数远远大于99次,需要消耗很长时间或者几乎不能生成;因此我们采取以下方式:产生的随机数当作是索引,索引对应数据范围的一个数据,每次生成一个随机数就减少一个数据,并且下次随机数生成范围也相应减小,这样需要n个随机数时我们只需要生成n次即可。

       如数据源是1 2 3 4 5 6 7 8 9 10     (基本数据集合)

       第1次产生随机数范围是1到10,假设第1次产生的随机数是5,把5当作是索引,在基本数据集合中取第5个,并将5移除。

       此时数据源变为 1 2 3 4 6 7 8 9 10

       第2次产生随机数范围是1到9,假设第2次产生的随机数是8,把8当作是索引,在基本数据集合中取第8个,并将9移除

       此时数据源变为 1 2 3 4 6 7 8 10        

       第3次产生随机数范围是1到8,假设第3次产生的随机数是6,把6当作是索引,在基本数据集合中取第6个,并将7移除

       此时数据源变为 1 2 3 4 6 8 10

        ......

        以此类推,直到选取的数据个数等于指定的个数。

 

     注:生成的随机数小于等于基本数据集合的数据个数。

 

六、附-C语言实现

#include <stdio.h>
#include <stdlib.h>
#include <time.h>   //随机生成用到time做种子

int INTVALID = -1;//当作是无效的 

int* baseArrPtr = NULL;//基本数据数组 

//从size大小的arrPtr集合中取第index个数据
int take(int* arrPtr, int size, int index)
{
	int i, j;
	if (NULL == baseArrPtr)
	{
		return  -1;
	}

	for (i = 0, j = 0; i<size; i++)
	{
		if (arrPtr[i] != INTVALID)
		{
			if (j == index)
			{
				j = arrPtr[i];
				arrPtr[i] = INTVALID;
				return j;
			}
			j++;
		}
	}
	return -1;
}

//从min到max范围内取cnt个数据并填充到arr
int getUniqueRandomArr(int arr[], int cnt, int min, int max)
{
	int i, j;
	int randNum;//随机数 
	int baseSize = max - min + 1;
	int tmpSize = baseSize;

	INTVALID = min - 1;

	if (min >= max)
	{
		return -1;
	}

	if (cnt>baseSize)
	{
		return -2;
	}

	if (NULL != baseArrPtr)
	{
		free(baseArrPtr);
	}

	//为基本数据数组分配空间 
	baseArrPtr = (int*)malloc(baseSize*sizeof(int));
	if (NULL == baseArrPtr)
	{
		return -3;
	}

	//初始化基本数据数组 
	for (i = 0, j = min; i < baseSize; i++, j++)
	{
		baseArrPtr[i] = j;
	}

	srand(time(0));//设置随机数种子 
				   //rand()%num产生 0~num-1
				   //rand产生范围数公式rand()%(m+1-n)+n;有效范围在 [n,m]
	for (i = 0; cnt>0; cnt--)
	{
		randNum = rand() % tmpSize;//randNum的有效范围在 [0,baseSize-1]	
		arr[i++] = take(baseArrPtr, baseSize, randNum);
		tmpSize--; 
	}

	free(baseArrPtr);
	return i;
}

int main(int argc, char *argv[])
{
	int  i;
	int min;
	int max;
	int cnt;
	int arr[128] = { 0 };
	printf("Please input min, max, count:");
	scanf("%d %d %d", &min, &max, &cnt);
	getUniqueRandomArr(arr, cnt, min, max);
	for (i = 0; i<cnt; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\nFinish.\n");
	//system("pause");
	return 0;
}

 效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值