FisherYates สุ่ม 基本思想(Knuth สุ่ม ):
หากต้องการสับเปลี่ยนอาร์เรย์ a จาก n องค์ประกอบ (ดัชนี 0..n-1):
สำหรับฉันจาก n − 1 ลงไป 1 do
j ← จำนวนเต็มสุ่มที่มี 0 ≤ j ≤ i
แลกเปลี่ยน a[j] และ a[i]
JDK 代码如下:
-
* ย้ายทุกองค์ประกอบของรายการไปยังตำแหน่งใหม่แบบสุ่มในรายการ
* ใช้เครื่องกำเนิดตัวเลขสุ่มที่ระบุ
-
* @รายการพารามิเตอร์
* รายการที่จะสับเปลี่ยน
* @param สุ่ม
* เครื่องกำเนิดตัวเลขสุ่ม
-
* @throws UnsupportedOperationException
* ไม่รองรับเมื่อแทนที่องค์ประกอบในรายการ
-
@SuppressWarnings("ไม่ได้เลือก")
สับเปลี่ยนโมฆะคงที่สาธารณะ (รายการ <?> รายการ, สุ่มสุ่ม) {
ถ้า (!(รายการอินสแตนซ์ของ RandomAccess)) {
วัตถุ[] array = list.toArray();
สำหรับ (int i = array.length - 1; i > 0; i--) {
ดัชนี int = Random.nextInt (i + 1);
ถ้า (ดัชนี < 0) {
ดัชนี = -ดัชนี;
-
อุณหภูมิวัตถุ = อาร์เรย์ [i];
อาร์เรย์ [i] = อาร์เรย์ [ดัชนี];
อาร์เรย์ [ดัชนี] = อุณหภูมิ;
-
อินท์ i = 0;
ListIterator<Object> it = (ListIterator<Object>) รายการ
.listIterator();
ในขณะที่ (it.hasNext()) {
it.ถัดไป();
it.set(อาร์เรย์[i++]);
-
} อื่น {
รายการ<วัตถุ> rawList = (รายการ<วัตถุ>) รายการ;
สำหรับ (int i = rawList.size() - 1; i > 0; i--) {
ดัชนี int = Random.nextInt(i + 1);
ถ้า (ดัชนี < 0) {
ดัชนี = -ดัชนี;
-
rawList.set(ดัชนี, rawList.set(i, rawList.get(ดัชนี)));
-
-
-
โมฆะคงที่สาธารณะหลัก (สตริงสุดท้าย args []) {
การเปลี่ยนแปลงวัตถุ Temp;
รายการ <จำนวนเต็ม> numList = ใหม่ ArrayList<จำนวนเต็ม>();
รายการ <จำนวนเต็ม> firstList = ใหม่ ArrayList<จำนวนเต็ม>();
รายการ <จำนวนเต็ม> SecondList = ใหม่ ArrayList<จำนวนเต็ม>();
รายการ <จำนวนเต็ม> ThirdList = ใหม่ ArrayList<จำนวนเต็ม>();
รายการ <จำนวนเต็ม> fourList = ใหม่ ArrayList<จำนวนเต็ม>();
สำหรับ (int i = 1; i <= 100000; i++) {
numList.add(i);
firstList.เพิ่ม(i);
SecondList.add(i);
ThirdList.add(i);
fourList.add(i);
-
// ขั้นแรก shuffle ให้ใช้ changeTemp
getStartTime();
int randInt = 0;
สำหรับ (int i = 0, length = firstList.size(); i < length; i++) {
randInt = getRandom(i, firstList.size());
changeTemp = firstList.get(i);
firstList.set(i, firstList.get(randInt));
firstList.set(randInt, javaShuffle.temp);
-
getEndTime("เวลาดำเนินการสับเปลี่ยนครั้งแรก ");
// สุ่มครั้งที่สอง รายการแลกเปลี่ยน
getStartTime();
สำหรับ (int i = 0, length = SecondList.size(); i <length; i++) {
randInt = getRandom(i, SecondList.size());
SecondList.set(i, SecondList.set(randInt, SecondList.get(i)));
-
getEndTime("เวลาดำเนินการสับเปลี่ยนครั้งที่สอง");
// สับเปลี่ยนครั้งที่สาม การเปลี่ยนแปลงสร้าง int แบบสุ่ม
getStartTime();
วัตถุ [] tempArray = ThirdList.toArray();
สุ่มแรนด์ = สุ่มใหม่ ();
อินท์เจ = 0;
สำหรับ (int i = tempArray.length - 1; i > 0; i--) {
เจ = rand.nextInt(i + 1);
ThirdList.set(i, ThirdList.set(j, ThirdList.get(i)));
-
getEndTime("เวลาทำงานสับเปลี่ยนครั้งที่สาม ");
// สับเปลี่ยนครั้งที่สี่ จำลองจาวาสับเปลี่ยน
getStartTime();
สุ่ม สุ่ม = สุ่มใหม่();
ถ้า (!(อินสแตนซ์รายการที่สี่ของ RandomAccess)) {
วัตถุ [] อาร์เรย์ = fourList.toArray ();
สำหรับ (int i = array.length - 1; i > 0; i--) {
ดัชนี int = Random.nextInt(i + 1);
ถ้า (ดัชนี < 0) {
ดัชนี = -ดัชนี;
-
อุณหภูมิวัตถุ = อาร์เรย์ [i];
อาร์เรย์ [i] = อาร์เรย์ [ดัชนี];
อาร์เรย์ [ดัชนี] = อุณหภูมิ;
-
อินท์ i = 0;
ListIterator<จำนวนเต็ม> it = (ListIterator<จำนวนเต็ม>) fourList.listIterator();
ในขณะที่ (it.hasNext()) {
it.ถัดไป();
it.set((จำนวนเต็ม) อาร์เรย์[i++]);
-
} อื่น {
รายการ <จำนวนเต็ม> rawList = (รายการ <จำนวนเต็ม>) รายการที่สี่;
สำหรับ (int i = rawList.size() - 1; i > 0; i--) {
ดัชนี int = Random.nextInt (i + 1);
ถ้า (ดัชนี < 0) {
ดัชนี = -ดัชนี;
-
rawList.set(ดัชนี, rawList.set(i, rawList.get(ดัชนี)));
-
-
getEndTime("เวลาทำงานสับเปลี่ยนครั้งที่สี่");
// จาวาสับเปลี่ยน
getStartTime();
คอลเลกชัน.สับเปลี่ยน(numList);
getEndTime("เวลาทำงานแบบสุ่มของ Java ");
-
การแลกเปลี่ยนโมฆะคงที่สาธารณะ (int a, int b) {
javaShuffle.temp = ก;
ก = ข;
ข = javaShuffle.temp;
-
int สาธารณะคงที่ getRandom (int สุดท้ายต่ำ, int สุดท้ายสูง) {
กลับ (int) (Math.random() * (สูง - ต่ำ) + ต่ำ);
-
โมฆะสาธารณะคงที่ getStartTime () {
javaShuffle.start = System.nanoTime();
-
โมฆะสาธารณะคงที่ getEndTime (สตริงสุดท้าย) {
javaShuffle.end = System.nanoTime();
System.out.println(s + ": " + (javaShuffle.end - javaShuffle.start) + "ns");
-
-
如果数值较小,例如100000级别,则输出大概是:
เวลารันการสับเปลี่ยนครั้งแรก: 85029499ns
เวลารันการสุ่มครั้งที่สอง: 80909474ns
เวลารันการสับเปลี่ยนครั้งที่สาม: 71543926ns
เวลารันการสุ่มครั้งที่สี่: 76520595ns
เวลารัน Java แบบสุ่ม: 61027643ns
เวลารันการสับเปลี่ยนครั้งแรก: 82326239ns
เวลารันการสุ่มครั้งที่สอง: 78575611ns
เวลารันการสับเปลี่ยนครั้งที่สาม: 95009632ns
เวลารันการสุ่มครั้งที่สี่: 105946897ns
เวลารัน Java สุ่ม: 90849302ns
เวลารันการสับเปลี่ยนครั้งแรก: 84539840ns
เวลารันการสุ่มครั้งที่สอง: 85965575ns
เวลารันการสุ่มครั้งที่สาม: 101814998ns
เวลารันการสุ่มครั้งที่สี่: 113309672ns
เวลารัน Java สุ่ม: 35089693ns
เวลารันการสับเปลี่ยนครั้งแรก: 87679863ns
เวลารันการสุ่มครั้งที่สอง: 79991814ns
เวลารันการสับเปลี่ยนครั้งที่สาม: 73720515ns
เวลารันการสุ่มครั้งที่สี่: 78353061ns
เวลารัน Java สุ่ม: 64146465ns
เวลารันการสับเปลี่ยนครั้งแรก: 84314386ns
เวลารันการสุ่มครั้งที่สอง: 80074803ns
เวลารันการสับเปลี่ยนครั้งที่สาม: 74001283ns
เวลารันการสุ่มครั้งที่สี่: 79931321ns
เวลารัน Java สุ่ม: 86427540ns
เวลารันการสับเปลี่ยนครั้งแรก: 84315523ns
เวลารันการสุ่มครั้งที่สอง: 81468386ns
เวลารันการสับเปลี่ยนครั้งที่สาม: 75052284ns
เวลารันการสุ่มครั้งที่สี่: 79461407ns
เวลารัน Java สุ่ม: 66607729ns
如果是10000000级别,大概如下:
เวลารันการสับเปลี่ยนครั้งแรก: 2115703288ns
เวลารันการสุ่มครั้งที่สอง: 3114045871ns
เวลารันการสับเปลี่ยนครั้งที่สาม: 4664426798ns
เวลารันการสุ่มครั้งที่สี่: 2962686695ns
เวลารัน java shuffle: 3246883026ns เวลารัน shuffle ครั้งแรก: 2165398466ns
เวลารันการสุ่มครั้งที่สอง: 3129558913ns
เวลารันการสับเปลี่ยนครั้งที่สาม: 4147859664ns
เวลารันการสุ่มครั้งที่สี่: 2911849942ns
เวลารัน java shuffle: 4311703487ns เวลารัน shuffle ครั้งแรก: 2227462247ns
เวลารันการสุ่มครั้งที่สอง: 3279548770ns
เวลารันการสับเปลี่ยนครั้งที่สาม: 4704344954ns
เวลารันการสุ่มครั้งที่สี่: 2942635980ns
เวลารัน java shuffle: 3933172427ns เวลารัน shuffle ครั้งแรก: 2200158789ns
เวลารันการสุ่มครั้งที่สอง: 3172666791ns
เวลารันการสับเปลี่ยนครั้งที่สาม: 4715631517ns
เวลารันการสุ่มครั้งที่สี่: 2950817535ns
เวลารัน java shuffle: 3387417676ns เวลารัน shuffle ครั้งแรก: 2201124449ns
เวลารันการสุ่มครั้งที่สอง: 3203823874ns
เวลารันการสับเปลี่ยนครั้งที่สาม: 4179926278ns
เวลารันการสุ่มครั้งที่สี่: 2913690411ns
เวลารัน java shuffle: 3571313813ns เวลารัน shuffle ครั้งแรก: 2163053190ns
เวลารันการสุ่มครั้งที่สอง: 3073889926ns
เวลารันการสับเปลี่ยนครั้งที่สาม: 4493831518ns
เวลารันการสุ่มครั้งที่สี่: 2852713887ns
เวลารัน Java สุ่ม: 3773602415ns
可以看出,第一种方法速度最快,而第四种最慢。java自带 shuffle速度也不理想。
在进行大数据处理的时候,如果使用java库效率较低时,可以考虑使用其他方式。