java隨機(jī)抽取指定范圍不重復(fù)的數(shù)字
本文給大家介紹如何在JAVA中實現(xiàn)隨機(jī)無重復(fù)數(shù)字的功能。如果您是初學(xué)者的話,有必要看一看這篇文章,因為這個功能一般會在面試中遇到。包括我本人在招聘人員的時候也喜歡拿這個問題去問別人,主要看一看考慮問題的模式和基礎(chǔ)知識如何。
希望這篇文章能給初次接觸的朋友一些幫助,因為我曾接觸過一些朋友要么寫不出來,要么使用很平鋪的思維方式去實現(xiàn)它。
一般有點開發(fā)經(jīng)驗的朋友都能實現(xiàn)這樣的功能,只不過是效率上的問題。我們一般在面對這樣的問題時,總會平鋪直序的聯(lián)想到,先生成一個數(shù)組,然后在一個循環(huán)中向數(shù)組中添加隨機(jī)數(shù)字,在添加數(shù)字的過程中先查找一下數(shù)組中是否存在這個數(shù)字,如果不存在這個數(shù)字就直接添加到數(shù)組中;如果存在這個數(shù)字就不添加。我們一般都是這樣考慮問題的,這樣考慮也能實現(xiàn)功能,我剛才也說了,只不過是效率上的問題。
為了更好地理解這個題意,我們先來看下具體內(nèi)容:生成一個1-100的隨機(jī)數(shù)組,但數(shù)組中的數(shù)字不能重復(fù),即位置是隨機(jī)的,但數(shù)組元素不能重復(fù)。
在這里呢,沒有給我們規(guī)定數(shù)組的長度,我們可以讓它是1-100之間的任意長度。
接下來讓我們看一下幾種實現(xiàn)方法并對這幾種方法作個對比。
通常我們會使用ArrayList或數(shù)組來實現(xiàn),先來看下ArrayList實現(xiàn)過程,如下面代碼所示:
import java.util.ArrayList; import java.util.Random; /** * 使用ArrayList實現(xiàn) * @Description: * @File: Demo.java * @Package None * @Author Hanyonglu * @Date 2012-10-18 下午06:16:55 * @Version V1.0 */ public class Demo { public static void main(String[] args) { Object[] values = new Object[20]; Random random = new Random(); ArrayList<Integer> list = new ArrayList<Integer>(); for(int i = 0; i < values.length;i++){ int number = random.nextInt(100) + 1; if(!list.contains(number)){ list.add(number); } } values = list.toArray(); // 遍歷數(shù)組并打印數(shù)據(jù) for(int i = 0;i < values.length;i++){ System.out.print(values[i] + "\t"); if(( i + 1 ) % 10 == 0){ System.out.println("\n"); } } } }
使用數(shù)組實現(xiàn)的過程如下所示代碼:
import java.util.Random; /** * 使用數(shù)組實現(xiàn) * @Description: * @File: Demo4.java * @Package None * @Author Hanyonglu * @Date 2012-10-18 下午06:27:38 * @Version V1.0 */ public class Demo4 { public static void main(String[] args) { int[] values = new int[20]; Random random = new Random(); for(int i = 0;i < values.length;i++){ int number = random.nextInt(100) + 1; for(int j = 0;j <= i;j++){ if(number != values[j]){ values[i]=number; } } } // 遍歷數(shù)組并打印數(shù)據(jù) for(int i = 0;i < values.length;i++){ System.out.print(values[i] + "\t"); if(( i + 1 ) % 10 == 0){ System.out.println("\n"); } } } }
上面這兩個實現(xiàn)過程效率比較低的。因為在每次添加時都要去遍歷一下當(dāng)前列表中是否存在這個數(shù)字,時間復(fù)雜度是O(N^2)。我們可以這樣思考一下:既然涉及到無重復(fù),我們可以想一下HashSet和HashMap的功能。HashSet實現(xiàn)Set接口,Set在數(shù)學(xué)上的定義就是無重復(fù),無次序的集合。而HashMap實現(xiàn)Map,也是不允許重復(fù)的Key。這樣我們可以使用HashMap或HashSet來實現(xiàn)。
在使用HashMap實現(xiàn)時,只需要將它的key轉(zhuǎn)化成數(shù)組就Ok了,如下代碼:
import java.util.HashMap; import java.util.Iterator; import java.util.Random; import java.util.Map.Entry; /** * 使用HashMap實現(xiàn) * @Description: * @File: Demo.java * @Package None * @Author Hanyonglu * @Date 2012-10-18 下午06:12:50 * @Version V1.0 */ public class Demo { public static void main(String[] args) { int n = 0; Object[] values = new Object[20]; Random random = new Random(); HashMap<Object, Object> hashMap = new HashMap<Object, Object>(); // 生成隨機(jī)數(shù)字并存入HashMap for(int i = 0;i < values.length;i++){ int number = random.nextInt(100) + 1; hashMap.put(number, i); } // 從HashMap導(dǎo)入數(shù)組 values = hashMap.keySet().toArray(); // 遍歷數(shù)組并打印數(shù)據(jù) for(int i = 0;i < values.length;i++){ System.out.print(values[i] + "\t"); if(( i + 1 ) % 10 == 0){ System.out.println("\n"); } } // Iterator iter = hashMap.entrySet().iterator(); // // 遍歷HashMap // while (iter.hasNext()) { // Entry<Integer, Integer> entry = (Entry)iter.next(); // int key = entry.getKey(); // n++; // // System.out.print(key + "\t"); // // if(n % 10 == 0){ // System.out.println("\n"); // } // } } }
由于HashSet和HashMap的關(guān)系太近了,HashSet在底層就是用HashMap來實現(xiàn)的,只不過沒有Value的集合,只有一個Key的集合,所以也可使用HashSet來實現(xiàn),如下代碼:
import java.util.HashSet; import java.util.Random; /** * 使用HashSet實現(xiàn) * @Description: * @File: Test.java * @Package None * @Author Hanyonglu * @Date 2012-10-18 下午06:11:41 * @Version V1.0 */ public class Test { public static void main(String[] args) { Random random = new Random(); Object[] values = new Object[20]; HashSet<Integer> hashSet = new HashSet<Integer>(); // 生成隨機(jī)數(shù)字并存入HashSet for(int i = 0;i < values.length;i++){ int number = random.nextInt(100) + 1; hashSet.add(number); } values = hashSet.toArray(); // 遍歷數(shù)組并打印數(shù)據(jù) for(int i = 0;i < values.length;i++){ System.out.print(values[i] + "\t"); if(( i + 1 ) % 10 == 0){ System.out.println("\n"); } } } }
這樣實現(xiàn)效率稍微好些。如果給我們限定了數(shù)組的長度,只需要變換下for循環(huán),設(shè)置成whlie循環(huán)就可以了。如下所示:
import java.util.HashSet; import java.util.Random; /** * 使用HashSet實現(xiàn) * @Description: * @File: Test.java * @Package None * @Author Hanyonglu * @Date 2012-10-18 下午05:11:41 * @Version V1.0 */ public class Test { public static void main(String[] args) { Random random = new Random(); Object[] values = new Object[20]; HashSet<Integer> hashSet = new HashSet<Integer>(); // 生成隨機(jī)數(shù)字并存入HashSet while(hashSet.size() < values.length){ hashSet.add(random.nextInt(100) + 1); } values = hashSet.toArray(); // 遍歷數(shù)組并打印數(shù)據(jù) for(int i = 0;i < values.length;i++){ System.out.print(values[i] + "\t"); if(( i + 1 ) % 10 == 0){ System.out.println("\n"); } } } }
我們可以把數(shù)組的長度設(shè)置成100,檢驗下運(yùn)行效果,如下圖所示:
以上幾種相比較而言,使用HashMap的效率是比較高的,其實是HashSet,再次是數(shù)組,最后是ArrayList。如果我們生成10000個數(shù)據(jù)將會發(fā)現(xiàn),使用HashMap花費(fèi)時間是:0.05s,HashSet是0.07s,數(shù)組是:0.20s,而ArrayList是0.25s。有興趣的可以設(shè)置下時間查看一下。
當(dāng)然了,除了使用HashMap實現(xiàn)外,還有其它高效的方法。比如,我們可以把1-100這些數(shù)字存儲在一個數(shù)組中,然后在for循環(huán)中隨機(jī)產(chǎn)生兩個下標(biāo),如果這兩個下標(biāo)不相等的話,可以交換數(shù)組中的元素,實現(xiàn)過程如下所示:
import java.util.Random; /** * 隨機(jī)調(diào)換位置實現(xiàn) * @Description: * @File: Demo4.java * @Package None * @Author Hanyonglu * @Date 2012-10-18 下午06:54:06 * @Version V1.0 */ public class Demo4 { public static void main(String[] args) { int values[] = new int[100]; int temp1,temp2,temp3; Random r = new Random(); for(int i = 0;i < values.length;i++){ values[i] = i + 1; } //隨機(jī)交換values.length次 for(int i = 0;i < values.length;i++){ temp1 = Math.abs(r.nextInt()) % (values.length-1); //隨機(jī)產(chǎn)生一個位置 temp2 = Math.abs(r.nextInt()) % (values.length-1); //隨機(jī)產(chǎn)生另一個位置 if(temp1 != temp2){ temp3 = values[temp1]; values[temp1] = values[temp2]; values[temp2] = temp3; } } // 遍歷數(shù)組并打印數(shù)據(jù) for(int i = 0;i < 20;i++){ System.out.print(values[i] + "\t"); if(( i + 1 ) % 10 == 0){ System.out.println("\n"); } } } }
這種方法也是比較高效的,如果生成10000個數(shù)據(jù),那么它所用的時間是0.054s。
在數(shù)組中利用坐標(biāo)來實現(xiàn)的基礎(chǔ)上可以變換更多相關(guān)的解決方法,具體地可以查閱相關(guān)資料。
以上是關(guān)于在JAVA中實現(xiàn)隨機(jī)無重復(fù)數(shù)字的功能,當(dāng)然方法也不僅限于這么幾種,還有其它的實現(xiàn)方法。希望能對接觸不久的朋友有所幫助,也希望能夠起到拋磚引玉的作用。
原文網(wǎng)址:http://www.cnblogs.com/hanyonglu/archive/2012/10/18/2730007.html
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解在Spring-Boot中實現(xiàn)通用Auth認(rèn)證的幾種方式
這篇文章主要介紹了詳解在Spring-Boot中實現(xiàn)通用Auth認(rèn)證的幾種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07詳解SpringMVC加載配置Properties文件的幾種方式
這篇文章主要介紹了詳解SpringMVC加載配置Properties文件的幾種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-02-02SpringMVC中controller接收json數(shù)據(jù)的方法
這篇文章主要為大家詳細(xì)介紹了SpringMVC中controller接收json數(shù)據(jù)的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09基于常用json框架介紹和Jackson返回結(jié)果處理方式
這篇文章主要介紹了基于常用json框架介紹和Jackson返回結(jié)果處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09解析ConcurrentHashMap: 預(yù)熱(內(nèi)部一些小方法分析)
ConcurrentHashMap是由Segment數(shù)組結(jié)構(gòu)和HashEntry數(shù)組結(jié)構(gòu)組成。Segment的結(jié)構(gòu)和HashMap類似,是一種數(shù)組和鏈表結(jié)構(gòu),今天給大家普及java面試常見問題---ConcurrentHashMap知識,一起看看吧2021-06-06Spring Boot緩存實戰(zhàn) EhCache示例
本篇文章主要介紹了Spring Boot緩存實戰(zhàn) EhCache示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08