采样问题
2015-04-08 11:06
169 查看
问题描述
从0~n-1中随机选取m(m < n)个不同整数,且使m个整数有序输出。已知条件
bigRand()产生一个远大于m和n的正整数;randInt(int i,int j)产生一个[i,j]的随机数;
sort(int []a,int lo,int hi)对a中指定范围内数据排序
解决方法
【Knuth的S算法】从r个剩余元素中选择s个元素,以s/r的概率选择下一个。/** * 从0~n-1中随机选取m个随机数,且m个随机数输出结果有序。 * 时间复杂度:O(n);空间开销:O(1) * 应用场景:n比较小 * @param m * @param n * */ public static void genKnuthS(int m,int n) { int select=m; int remaining=n; for(int i=0;i<n;i++) { //从r个剩余的整数中选择s个,以s/r的概率选择下一个 if((bigRand()%remaining)<select) { System.out.println(i); select--; } remaining--; } }
随机整数插入有序集合,丢掉大量重复随机数
/** * 随机整数插入有序集合 * 时间复杂度:O(mlogm);空间开销:集合存储开销。 * 应用场景:适合m相对n较小情况 * @param m * @param n */ public static void genSets(int m,int n) { //使用Integer包装类,不如C++效率高 Set<Integer>S=new TreeSet<>(); //m个不同随机数插入到集合中,丢掉重复的随机数 while(S.size()<m) S.add(bigRand()%n); //遍历集合,随机数有序输出 for(int i:S) System.out.println(i); }
【Floyd算法】随机整数插入有序集合,如果出现重复随机数,用本轮最大随机数代替,保证只选取m次
/** * 随机整数插入有序集合 * 时间复杂度:O(mlogm);空间开销:集合存储开销 * 应用场景:m相对与n较小(最坏情况也只进行m次选取) * @param m * @param n */ public static void genFloyd(int m,int n) { Set<Integer> S=new TreeSet<>(); int t; for(int i=n-m;i<n;i++) { t=bigRand()%(i+1); if(!S.contains(t)) S.add(t); else S.add(i);//出现重复,选择本轮最大随机数,i一定不再集合中 } //遍历集合,随机数有序输出 for(int i:S) System.out.println(i); }
【Knuth P算法】打乱包含0~n-1个整数的数组,前m个元素排序输出。不足:可能存在重复的随机数。
/** * 打乱包含0~n-1个整数的数组,前m个元素排序输出 * 时间复杂度:O(n+mlogm);空间复杂度:O(n) * @param m * @param n */ public static void genKnuthP(int m,int n) { int []a=new int ; for(int i=0;i<n;i++) a[i]=i; //对n个元素进行洗牌 for(int j=0;j<n;j++) { //交换a[j]、a[rand] int rand=randInt(j,n-1); int t=a[j]; a[j]=a[rand]; a[rand]=t; } //前m个元素排序输出,其中可能存在重复元素 sort(a,0,m-1); for(int k=0;k<m;k++) System.out.println(a[k]); }
【Knuth P’算法】只对前m个元素进行洗牌,并排序输出。
/** * 打乱数组中前m个元素,并排序输出 * @param m * @param n */ public static void genShuf(int m,int n) { int []a=new int ; for(int i=0;i<n;i++) a[i]=i; //前面个元素进行洗牌 for(int j=0;j<m;j++) { //a[j]<-rand、a[rand]<-j int rand=randInt(j,n-1); a[j]=rand; a[rand]=j; } //前m个元素排序输出,其中可能存在重复元素 sort(a,0,m-1); for(int k=0;k<m;k++) System.out.println(a[k]); }
补充
bigRand()的一种实现/** * 产生很大的随机整数 * @return */ private static int bigRand() { return (int)(Integer.MAX_VALUE*r.nextDouble()+r.nextDouble());//r为Random类的一个实例对象; }
randInt(int i,int j)的一种实现
/** * 返回[i..j]范围内均匀选择的随机整数 * @param i * @param j * @return */ private static int randInt(int i,int j) { return i+(int)(r.nextDouble()*(j-i+1)); //return i+bigRand()%(j-i+1); }
sort(int []a,int lo,int high) 一种快排的实现
/** * 对数组下标lo...hi之间的元素进行快速排序 * @param a 待排序数组 * @param lo 最低位 * @param hi 最高位 */ public static void sort(int[] a,int lo,int hi){ if(hi<=lo)return; int j=partition(a,lo,hi); sort(a,lo,j-1); sort(a,j+1,hi); } /** * 一次划分 * @param a 待排序数组 * @param lo 最低位 * @param hi 最高位 * @return 划分点 */ private static int partition(int []a,int lo,int hi){ int i=lo,j=hi+1; int v=a[lo]; //最低位的元素作为划分点 while(true){ while(less(a[++i],v)) if(i==hi) break; while(less(v,a[--j])) if(j==lo) break; if(i>=j)break; exch(a,i,j); } exch(a,lo,j); return j; }
总结
一般来说采用knuth 的S或Floyd算法可以很好的解决这类有限集合非空真子集的选取问题。相关文章推荐
- 解决 ORACLE 11.2 动态采样导致的性能问题
- 色度上采样错误和4:2:0隔行扫描色度问题(一)
- STM32F030 ADC1的DMA采样问题
- oprofile抓不到采样数据问题和解决方法
- 音频信号中采样率和比特率以及采样编码的问题
- AD采样问题总结
- 概率和随机数经典面试问题:拒绝采样,蓄水池抽样,洗牌问题和随机01问题
- 数据流基本问题---采样问题
- 钢琴多层采样问题及解决方案
- 色度上采样错误和4:2:0隔行扫描色度问题(二)
- 采样问题
- 解决龙芯2F使用oprofile-0.9.7无法采样应用程序函数的问题
- PMSM3_1的电流采样问题
- 编程珠玑——第12章,采样问题,学习笔记
- use_concat导致not in时临时表不动态采样进而导致的性能问题
- ALSA的采样频率不一致问题
- 音频采样位数问题
- CD为什么采用44.1kHz采样频率的问题
- 430_AD采样不准确问题
- STM8L051之ADC+DMA两通道数据采样错位问题