java隨機(jī)抽取指定范圍不重復(fù)的數(shù)字
本文給大家介紹如何在JAVA中實(shí)現(xiàn)隨機(jī)無(wú)重復(fù)數(shù)字的功能。如果您是初學(xué)者的話,有必要看一看這篇文章,因?yàn)檫@個(gè)功能一般會(huì)在面試中遇到。包括我本人在招聘人員的時(shí)候也喜歡拿這個(gè)問(wèn)題去問(wèn)別人,主要看一看考慮問(wèn)題的模式和基礎(chǔ)知識(shí)如何。
希望這篇文章能給初次接觸的朋友一些幫助,因?yàn)槲以佑|過(guò)一些朋友要么寫不出來(lái),要么使用很平鋪的思維方式去實(shí)現(xiàn)它。
一般有點(diǎn)開發(fā)經(jīng)驗(yàn)的朋友都能實(shí)現(xiàn)這樣的功能,只不過(guò)是效率上的問(wèn)題。我們一般在面對(duì)這樣的問(wèn)題時(shí),總會(huì)平鋪直序的聯(lián)想到,先生成一個(gè)數(shù)組,然后在一個(gè)循環(huán)中向數(shù)組中添加隨機(jī)數(shù)字,在添加數(shù)字的過(guò)程中先查找一下數(shù)組中是否存在這個(gè)數(shù)字,如果不存在這個(gè)數(shù)字就直接添加到數(shù)組中;如果存在這個(gè)數(shù)字就不添加。我們一般都是這樣考慮問(wèn)題的,這樣考慮也能實(shí)現(xiàn)功能,我剛才也說(shuō)了,只不過(guò)是效率上的問(wèn)題。
為了更好地理解這個(gè)題意,我們先來(lái)看下具體內(nèi)容:生成一個(gè)1-100的隨機(jī)數(shù)組,但數(shù)組中的數(shù)字不能重復(fù),即位置是隨機(jī)的,但數(shù)組元素不能重復(fù)。
在這里呢,沒(méi)有給我們規(guī)定數(shù)組的長(zhǎng)度,我們可以讓它是1-100之間的任意長(zhǎng)度。
接下來(lái)讓我們看一下幾種實(shí)現(xiàn)方法并對(duì)這幾種方法作個(gè)對(duì)比。
通常我們會(huì)使用ArrayList或數(shù)組來(lái)實(shí)現(xiàn),先來(lái)看下ArrayList實(shí)現(xiàn)過(guò)程,如下面代碼所示:
import java.util.ArrayList;
import java.util.Random;
/**
* 使用ArrayList實(shí)現(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ù)組實(shí)現(xiàn)的過(guò)程如下所示代碼:
import java.util.Random;
/**
* 使用數(shù)組實(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");
}
}
}
}
上面這兩個(gè)實(shí)現(xiàn)過(guò)程效率比較低的。因?yàn)樵诿看翁砑訒r(shí)都要去遍歷一下當(dāng)前列表中是否存在這個(gè)數(shù)字,時(shí)間復(fù)雜度是O(N^2)。我們可以這樣思考一下:既然涉及到無(wú)重復(fù),我們可以想一下HashSet和HashMap的功能。HashSet實(shí)現(xiàn)Set接口,Set在數(shù)學(xué)上的定義就是無(wú)重復(fù),無(wú)次序的集合。而HashMap實(shí)現(xiàn)Map,也是不允許重復(fù)的Key。這樣我們可以使用HashMap或HashSet來(lái)實(shí)現(xiàn)。
在使用HashMap實(shí)現(xiàn)時(shí),只需要將它的key轉(zhuǎn)化成數(shù)組就Ok了,如下代碼:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import java.util.Map.Entry;
/**
* 使用HashMap實(shí)現(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來(lái)實(shí)現(xiàn)的,只不過(guò)沒(méi)有Value的集合,只有一個(gè)Key的集合,所以也可使用HashSet來(lái)實(shí)現(xiàn),如下代碼:
import java.util.HashSet;
import java.util.Random;
/**
* 使用HashSet實(shí)現(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");
}
}
}
}
這樣實(shí)現(xiàn)效率稍微好些。如果給我們限定了數(shù)組的長(zhǎng)度,只需要變換下for循環(huán),設(shè)置成whlie循環(huán)就可以了。如下所示:
import java.util.HashSet;
import java.util.Random;
/**
* 使用HashSet實(shí)現(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ù)組的長(zhǎng)度設(shè)置成100,檢驗(yàn)下運(yùn)行效果,如下圖所示:

以上幾種相比較而言,使用HashMap的效率是比較高的,其實(shí)是HashSet,再次是數(shù)組,最后是ArrayList。如果我們生成10000個(gè)數(shù)據(jù)將會(huì)發(fā)現(xiàn),使用HashMap花費(fèi)時(shí)間是:0.05s,HashSet是0.07s,數(shù)組是:0.20s,而ArrayList是0.25s。有興趣的可以設(shè)置下時(shí)間查看一下。
當(dāng)然了,除了使用HashMap實(shí)現(xiàn)外,還有其它高效的方法。比如,我們可以把1-100這些數(shù)字存儲(chǔ)在一個(gè)數(shù)組中,然后在for循環(huán)中隨機(jī)產(chǎn)生兩個(gè)下標(biāo),如果這兩個(gè)下標(biāo)不相等的話,可以交換數(shù)組中的元素,實(shí)現(xiàn)過(guò)程如下所示:
import java.util.Random;
/**
* 隨機(jī)調(diào)換位置實(shí)現(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)生一個(gè)位置
temp2 = Math.abs(r.nextInt()) % (values.length-1); //隨機(jī)產(chǎn)生另一個(gè)位置
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個(gè)數(shù)據(jù),那么它所用的時(shí)間是0.054s。
在數(shù)組中利用坐標(biāo)來(lái)實(shí)現(xiàn)的基礎(chǔ)上可以變換更多相關(guān)的解決方法,具體地可以查閱相關(guān)資料。
以上是關(guān)于在JAVA中實(shí)現(xiàn)隨機(jī)無(wú)重復(fù)數(shù)字的功能,當(dāng)然方法也不僅限于這么幾種,還有其它的實(shí)現(xiàn)方法。希望能對(duì)接觸不久的朋友有所幫助,也希望能夠起到拋磚引玉的作用。
原文網(wǎng)址:http://www.cnblogs.com/hanyonglu/archive/2012/10/18/2730007.html
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java弱引用(WeakReference)的理解與使用
這篇文章主要介紹了Java弱引用(WeakReference)的理解與使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
Maven pom.xml 添加本地jar包依賴以及打包方法
這篇文章主要介紹了Maven pom.xml 添加本地jar包依賴以及打包方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
java 數(shù)據(jù)結(jié)構(gòu)中棧結(jié)構(gòu)應(yīng)用的兩個(gè)實(shí)例
這篇文章主要介紹了java 數(shù)據(jù)結(jié)構(gòu)中棧結(jié)構(gòu)應(yīng)用的兩個(gè)實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-06-06

