2015年6月30日 星期二

[Java]樂透抽取程式

這是一個很經典的題目,從1~49,
隨機抓取六個不同的數字
在Java上要隨機抽取數字不難,用 java.util.Random()或是Math.random()都可以 
我是習慣用Math.random()這個方法
Math.random()的取值是0<=Math.random()<1,所以要取1~49必須要寫成
Math.random()*49+1,那個範圍在0<=Math.random()*49+1<50
接著傳出的數值是double,所以要轉成int,取六個數字的程式碼就會變成這樣

  int[] random = new int[6];
for(int i=0;i<6;i++){
random[i]=(int)Math.floor(Math.random()*49+1);

}

接著上述抽取的數字會有重覆的問題,最簡單的解法就是去找之前的數字有沒有重覆,有重覆就重抽一個數字,如範例:

public class Random {

public static void main(String[] args) {

int[] random = new int[6];
for(int i=0;i<6;i++){
random[i]=(int) Math.floor(Math.random()*49+1);
for(int j=0;j<i;j++){//檢查有無重覆
if(random[i]==random[j]){//有重覆重抽一次
i--;
break;
}
}
}
System.out.println("result is:");
for(int x=0;x<6;x++){
System.out.print(random[x]+" ");
}
}
}


這個方法有個小缺點,比如說1000顆球取一千顆時,後面會重覆過多一直重抽數字
如果要解決這個情形可以用以下的解法
比如說10顆球抽3顆。一開始我們先將陣列排好成下面這樣
1 2 3 4 5 6 7 8 9 10
隨機1~10,假設抽到的是7號,我們就將第1個位置跟第7個位置交換
7 2 3 4 5 6 1 8 9 10
接著隨機2~10,假設抽到的是5號,接著將第2個位置跟第5個位置交換
7 5 3 4 2 6 1 8 9 10
再來隨機3~10,抽到的如果是5號,就將第3個位置跟第5個位置交換
7 5 2 4 3 6 1 8 9 10
最後抽到的三顆球就是打底線這三顆

最後我將總共的球數和抽取球數寫成鍵盤輸入,程式碼如下:

public class RandomApi {

public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("please input the number of balls:");
int balls= input.nextInt();
System.out.println("please input how many balls you want to pick:");
int picks= input.nextInt();
int [] result = RandomNumberPerduce(balls, picks);
for(int i=0;i<picks;i++){
System.out.print(result[i]+" ");
}
input.close();
}


//random value
private static int[] RandomNumberPerduce(int x1, int x2){

int[] random= new int[x1];
if(x2>x1){
System.out.println("Sorry, the number of balls is less then the number you want to pick up");
return random;
}
for(int i=0;i<x1;i++){
random[i]=i+1;
}

for(int i=0;i<x2;i++)
{
int result=(int) Math.floor(Math.random()*(x1-i)+i);
int temp = random[result];
random[result]=random[i];
random[i]= temp;

}
return random;
}


}//end of class

3 則留言:

  1. 想請問一下,為什麼這邊要加break呢?如果沒加會有甚麼問題? 謝謝
    if(random[i]==random[j]){//有重覆重抽一次

    i--;

    break;

    }

    回覆刪除
    回覆
    1. break這邊要整段一起看

      for(int j=0;j<i;j++){//檢查有無重覆

      if(random[i]==random[j]){//有重覆重抽一次

      i--;

      break;

      }

      }


      因為你已經檢查到有重複的資料了,所以確定要重抽後面就不用看了
      break可以跳出這個for迴圈
      節省不必要的檢查時間

      刪除
    2. 想了好久,原來是這樣,感謝您的詳細說明!!

      刪除