下面是我生成1到100之间不重复的随机数呢的代码,(规定用数组,不是用其它集合框架)可是总有一个回重复,不知道问题在哪里,请指点一二,谢谢:
代码:import java.util.*;public class Test {
public static void main(String[] args) {
int[] ints = new int[100];
for(int i=0;i<100;i++) {
int temp = (int) (Math.random()*100+1);
for(int j=0;j<100;j++) {
if(temp==ints[j]) {
temp = (int) (Math.random()*100+1);
j=0;
}
}
ints[i]=temp;
}
Arrays.sort(ints);
for(int index:ints) {
if(index%10==0)
System.out.println();
System.out.print(index+" ");
}
}}
代码:import java.util.*;public class Test {
public static void main(String[] args) {
int[] ints = new int[100];
for(int i=0;i<100;i++) {
int temp = (int) (Math.random()*100+1);
for(int j=0;j<100;j++) {
if(temp==ints[j]) {
temp = (int) (Math.random()*100+1);
j=0;
}
}
ints[i]=temp;
}
Arrays.sort(ints);
for(int index:ints) {
if(index%10==0)
System.out.println();
System.out.print(index+" ");
}
}}
解决方案 »
- 批量载入图片内存溢出怎么解决?
- 使用HttpURLConnection连接http服务器,如何判断是否连接成功
- javascritp问题
- DBconn.executeQuery:[Microsoft][SQLServer 2000 Driver for JDBC]Error establishin
- 函数返回值的问题,为什么TRY里的语句没起到作用~~~~~~,请帮我看看,谢谢
- 问一个简单问题
- 互斥的存/取款线程设计,为什么运行一直没有想要的结果?
- 我的JB6,在输入代码时,光标总是靠前一个字符???
- 看着大家说“java不是要去学的,而是要去用的”但是大家说的接项目去那里接呀?
- 如何让PopupMenu向上弹出?100分相送
- java里面用assert多不多
- http服务器
改成for(int j=0;j <i;j++) 就可以了
用“洗牌”方法最关键的一点,就是要抽出多少对数据交换多少次,简称(洗多少次牌?)。
理论上,至少洗 n/2 次才能洗到所有的牌。
但是,事实上,如果只洗 n/2 次,出现 没洗完所有牌 的几率很大当然,如果出现一张至几张牌 还是在原来的位置,这种情况是绝对允许的。下面,我贴了个算法,得出三组数据 比较两种 取随机数的方法。
数据表示有多少个数据在原位置上取n/2对数据交换
0 0 0 2 2 2 3 1 0 1
375 346 361 371 370 380 378 378 358 367取n对数据交换
0 2 0 2 1 0 0 2 1 1
120 139 147 147 126 133 144 139 132 140取n*n对数据交换
2 2 0 0 0 2 1 0 1 1
0 1 0 0 3 2 1 0 0 1public class Main {
public Main () {
start ();
}
public static void main (String[] args) {
new Main ();
}
private void start () {
for (int i = 0; i < m; i++) {
//
for (int j = 0; j < n; j++) {
iarr[j] = 0;
}
iarr_1[i][0] = g_1 ();
//
for (int j = 0; j < n; j++) {
iarr[j] = j;
}
iarr_1[i][1] = g_2 ();
}
for (int i = 0; i < 2; i++) {
for (int j = 0; j < m; j++) {
System.out.printf("%1$5s", iarr_1[j][i]);
}
System.out.println("");
}
}
private int g_1 () {
int j = 0;
while(j < n-1) {
int x = r.nextInt (n);
if (iarr[x] == 0) {
j++;
iarr[x] = j;
}
}
return check ();
}
private int g_2 () {
for (int i = 0; i < n*n; i++) {
int x = r.nextInt (n);
int y = r.nextInt (n);
{
int c = iarr[x];
iarr[x] = iarr[y];
iarr[y] = c;
}
}
return check ();
}
private int check () {
int j = 0;
for (int i = 0; i < n; i++) {
if (iarr[i] == i) {
j++;
}
}
return j;
}
private final int n = 1000;
private int[] iarr = new int[n];
private final int m = 10;
private int[][] iarr_1 = new int[m][2];
private java.util.Random r = new java.util.Random ();
}
(比较了 10 次)
第二排 使用 交换的方法。 也就是说 ,在0~999中,交换了(n/2 = 500)次。
结果总有 350 个数据左右在原位置。
这和 用抽牌的原理 取随机数的差距实在是太大了。
如果 n = 100 ,可能 几十次就可以了。但是当 n 不确定时,你就不能确定,到底要换多少次
如果 n 为 1000, 交换 1000 次,和第一种方法比较,就得以下数据。
0 2 0 2 1 0 0 2 1 1
120 139 147 147 126 133 144 139 132 140 数据相差之大,绝对不可取。
我测试的结果是,n = 1000,交换 n*n 次,得的结果才几乎和第一种方法相近。洗牌原理的缺点就在于,你是随机从 n 张牌种抽两张牌。
抽了 n 次可能有多张牌根本就没抽出来,
这和抽了两张牌 交换位置,结果牌又到原位置上有本质区别
但是,如果抽的 次数 > f(n) ,就一定可以得到接近于 第一种方法的随机性
可,问题就是 f(n) 不知道是多少的。我测的结果是 f(n) = n*n
可能比这个大,也可能比这个小至于,LS 说 第一种算法 效率低。
我是不赞同的。上面贴的 第一个函数的算法
随机生成0~999999 中的不重复数,只用了2秒(效率很高)
当然,随着 n 的增加,效率会越来越低。
不过,到那时候,也还可以在考虑算法的优化
我的问题和洗牌是有区别的!
洗拍是已经确定了有固定的54张牌,再随机的产生这54张派的顺序!请注意,我所说的是从任意整数中(正整数和负整数)取出100个数,这100个数必须是1-100的不重复数字,所以我的这一百个数在每次取的是否首先要判断它是否在1到100之间,而不是一定确定它是1到100之间某一个数。
我代码的思路,我想大家都很明白,我就不在罗嗦!
我产生随机数后只是排序后输出,方便我查看!可总是有一个数字会重复,我总是找不出原因(我的代码好象也没什么问题),至于二楼朋友说的 for(int j=0;j <i;j++) 其实也就是循环次数少了,但结果一样!
希望各位再帮帮忙!
temp = (int) (Math.random()*100+1);
j=0;
中的j=0;改成j=-1就可以了。
我想如果是固定了1-100
那产生随机数当然就很容易了,
我把1-100存到一个集合里,随机get集合中的一个数字,再从集合中remove(),如此循环,保证不会有重复的数字!
这方法怎么样?回答16楼:
j=-1,那我再判断时不就越界限了吗?不过谢谢你的提醒!
我想如果是固定了1-100
那产生随机数当然就很容易了,
我把1-100存到一个集合里,随机get集合中的一个数字,再从集合中remove(),如此循环,保证不会有重复的数字!
这方法怎么样? 回答16楼:
j=-1,那我再判断时不就越界限了吗?而且我j=0同样可以判断第一个数是否重复啊!
--------
想法没错。但是第一次你是生成0-99的下标,第二次是生成0-98的,因为去掉一个了,以此类推。一共要循环99次,因为最后一次就剩一个了,不用随机数了。
其实用这个办法的话,在原位也可以做,就是用交换的办法,是一样的。第一次生成0-99的下标,把这个下标的数和下标为99的数互换,第二次生成0-98的下标,把这个下标的数和下标为98的数互换,依次类推,也是需要99次循环。你的这个想法,我以前就考虑过,因为效率低,所以我没采用。用我说的办法,只要循环50-70次就足够了,满足绝大部分需要了,没必要99次。abc130314 提到有留在原位没有被交换的数,没有意义,这并不能完全代表乱的程度。除非你的随机数就那么凑巧,我觉得这种可能性不大。如果你说要完全避免,那是不可能的,你的任何算法都会出现随机数不“随机”,弄出规律来的情况。如果非要检测留在原位的数,那也不是数出有多少个留在原位的数的个数,而是看这些位置是不是总是不变,如果一直在变,那说明就洗牌够乱了,如果有大部分总是不变,那才能说明不够乱。
1~n 张牌中,任选一张牌 K
因为抽牌是有 放回的。
就以假设 抽两张牌为例做 X 次实验,每次实验 抽Y次牌那么,K 在每一此抽牌的过程中,都有(1/n)*(1/n) = p(a) 的几率不被抽中即,做了 X 次实验,每次实验抽 Y 次牌
那么 K 总不被抽中的几率 即为 p(a)^y ^x = p(A)p(A) = p(a)^y^x = ((1/n)*(1/n))^y ^x
严格意义来说,只要 n>1 ,p(A) 绝对不等于 0。
由此看来,这完全是 天大的错误。
假设 K = 54,
那么 54 总以 p(A) 的概率不被抽中。
那么,意思就是说,你只拿了前 53 张牌来做随机实验
(因为 54 总不被抽到,所有 54 一直在牌的最下面)但是,从某种意义上来说,等于 0 是永远不可能的。
不过可以让 p(A)趋进于 0 , 这是完全可以的。
只要 p(A)趋进于 0 ,那么也就达到了随机的效果。
(但是,抽牌算法只是做一次实验,所以,就必须要求 Y 足够大,以至能是 p(A)趋进于 0 )
至于 Y 到底要多大,可以 用 高数 求出来。
不过,如果你只是,以个人经验认为,100个随机数,抽 个“七八十次”,那么这个数据是绝对不够严谨的。
虽然,可能, 100个随机数,也许求出来,Y<70 。
但是,对于 n个随机数,你就完全无法确定 Y。
如果你以 100个数随机的比例,认为 0.7n <= y <= 0.8n
那么,我可以说,你绝对是 错的但是,如果用我上面类似的算法。就完全避免了这个问题。
因为,每次都是从 剩下的牌中抽牌,所有就完全 避免了 某一个牌不会随机抽不到的问题。
可以说 p(A) 绝对等于 0。
虽然这种方法也有很小的几率会随机成 1,2,...54 的队列
但是,这完全和 抽牌方法的 完全没有抽到某张牌事件 有本质的区别。不过,话说回来。
如果 能求出一个函数 f(n) = y ,能让 p(A)趋进于 0。
那么,第二种方法也是可取的。复杂度,也会比第一种方法小得多。
上面 p(A) 算小了
p(A) = p(a)^y^x = ( (n-1)/n * (n-1)/n )^y ^x
不被抽中的几率应该有这么大
基本思想就是for each i:1-->n, swap(value[i], value[random(i, n)])
对于第i次随机选到的元素,有i个独立的随机事件,分别是i-1次未选中和1次选中
事件发生的概率=((n-1)/n)*((n-2)/(n-1))* …… *((n-i+1)/(n-i+2))*(1/(n-i+1)) = 1/n
所以每个元素的事件发生都是等概率的,而且时间复杂度线性。
这是算法导论上的一个例子import java.util.*;public class Randomize
{
public static final int MAX_SIZE = 100;
public static final int MAX_VALUE = 100;
public static void main(String [] args)
{
//Initialize the array
int [] value = new int[MAX_SIZE];
for(int i=0; i<value.length; i++)
{
value[i] = i+1;
}
//Randomize the Array
randomize(value);
for(int i=0; i<value.length; i++)
{
if(i%10 == 0)
System.out.println("");
System.out.print(value[i]+" ");
}
}
public static void randomize(int [] value)
{
Random r = new Random();
for(int i=0; i<value.length-1; i++)
{
int index = r.nextInt(MAX_VALUE-i)+i;
int temp = value[i];
value[i] = value[index];
value[index] = temp;
}
}
}
不能以某张牌位置没变来说明一副牌被打乱的程度。
来说。(个人认为,这个说法不全面。)从根本来看。第 n 张牌,被放在n位置的概率 ,一定是 p(a) = 1/n
但是,你的方法 产生 的概率,p(a) = 不被洗到的概率 + 被洗到原位置的概率。不被洗到的概率 = ((n-1)/n * (n-1)/n )^y
假设,被洗到 原位置的概率 = p(b) ( p(b) > 0 )
那么 你的方法,产生的概率 p(a) = ((n-1)/n * (n-1)/n )^y + p(b)
因为,p(b) > 0
所以,可以100%肯定,
如果 ((n-1)/n * (n-1)/n )^y > 1/n,那么,洗牌打乱顺序就一定是错的。这样,你应该明白了吧。
洗牌就是一定 要 y 足够大。
如果你不能确定 y 对于 n 来说,怎样才算足够大。
那么,你这个题目,就没法继续做了。
0 2 0 2 1 0 0 2 1 1
120 139 147 147 126 133 144 139 132 140 对于,n = 1000, y = 1000
所求得的概率 p(a) 和 1/n
这差别有多大
{
public static final int MAX_SIZE = 100;
public static final int MAX_VALUE = 100; public static void main(String [] args)
{
//Initialize the array
int [] value = new int[MAX_SIZE];
for(int i=0; i <value.length; i++)
{
value[i] = i+1;
} //Randomize the Array
randomize(value); for(int i=0; i <value.length; i++)
{
if(i%10 == 0)
System.out.println("");
System.out.print(value[i]+" ");
}
}
public static void randomize(int [] value)
{
Random r = new Random();
for(int i=0; i <value.length-1; i++)
{
int index = r.nextInt(MAX_VALUE);
int temp = value[i];
value[i] = value[index];
value[index] = temp;
}
}
}