บทนี้จะอธิบายหลายวิธีในการสร้างตัวเลขสุ่ม Java จากนั้นแสดงให้เห็นผ่านตัวอย่าง
ภาพรวม:
คุณจะพูดที่นี่ความยากลำบากในการสร้างตัวเลขสุ่มคืออะไร? การใช้ Java Encapsulated แบบสุ่มไม่ใช่หรือไม่ แน่นอนว่ามันก็โอเคโดยทั่วไปและอัลกอริทึมที่จะอธิบายในบทความนี้ก็ขึ้นอยู่กับฟังก์ชั่นห้องสมุดแบบสุ่มนี้
บทความนี้ส่วนใหญ่มุ่งเน้นไปที่พฤติกรรมของการสุ่มตัวอย่างและการสุ่มตัวอย่างเองมีกฎโดยนัยที่ไม่มีข้อมูลซ้ำ ตกลงด้วยคำแนะนำเหล่านี้ ก่อนอื่นคุณสามารถลองใช้ความคิดของคุณเองเพื่อสร้างตัวเลขสุ่มโดยไม่ต้องสร้างซ้ำ
อัลกอริทึมพยายาม:
อัลกอริทึมที่ดีบางอย่างปรากฏขึ้นมักจะมาพร้อมกับอัลกอริทึมที่ไม่ดี อย่างไรก็ตามสำหรับอัลกอริทึมที่ไม่มีประสิทธิภาพมากโดยทั่วไปจะมีคุณสมบัติทั่วไปหนึ่งอย่างซึ่งง่ายต่อการเข้าใจและนำไปใช้ ต่อไปนี้เป็นคำอธิบายสั้น ๆ ผ่านวิธีการทีละขั้นตอน
ลองก่อน: อัลกอริทึมสุ่มไร้เดียงสา
อัลกอริทึมนี้เข้าใจง่ายมันสุ่ม! ทุกครั้งที่มีการสร้างหมายเลขสุ่มและเพิ่มลงในชุด
โมฆะส่วนตัวง่ายๆ (int start, int end, int count) {system.out.println ("อัลกอริทึมแบบสุ่มธรรมชาติ:"); StringBuffer buffer = new StringBuffer (); สำหรับ (int i = 0; i <count; i ++) {int random = numberutils.randominteger (เริ่มต้นสิ้นสุด); buffer.append (i == 0? ("[" + สุ่ม): ("," + สุ่ม)); } buffer.append ("]"); System.out.println (บัฟเฟอร์); - ความพยายามครั้งที่สอง: ตรวจสอบอัลกอริทึมแบบสุ่มที่มีอยู่จริง
เรารู้ว่ามีปัญหากับวิธีการข้างต้นนั่นคืออาจมีข้อมูลซ้ำกัน ดังนั้นเราจึงนึกถึงการตรวจสอบว่ามีจำนวนอยู่แล้วเมื่อสร้างหมายเลขสุ่มและถ้ามีอยู่มันจะถูกสร้างใหม่
Void Private CheckRandom (int start, int end, int count) {system.out.println ("ตรวจสอบอัลกอริทึมแบบสุ่มที่มีอยู่:"); StringBuffer buffer = new StringBuffer (); รายการ <จำนวนเต็ม> บันทึก = new ArrayList <> (); สำหรับ (int i = 0; i <count; i ++) {int random = numberutils.randominteger (เริ่มต้นสิ้นสุด); ถ้า (ออก (บันทึก, สุ่ม)) {i--; ดำเนินการต่อ; } save.add (สุ่ม); buffer.append (i == 0? ("[" + สุ่ม): ("," + สุ่ม)); } buffer.append ("]"); System.out.println (บัฟเฟอร์); - ความพยายามครั้งที่สาม: อัลกอริทึมการกำจัดองค์ประกอบแบบสุ่ม
อัลกอริทึมข้างต้นได้แก้ไขปัญหาของการทำซ้ำข้อมูล อย่างไรก็ตามปัญหาหนึ่งที่แย่มากคืออาจใช้เวลานานในการสร้างตัวเลขสุ่มตัวอย่าง (ขึ้นอยู่กับใบหน้า ... )
อย่างไรก็ตามที่นี่เรามีแนวคิดใหม่ นั่นคือการสุ่มใช้ตัวเลขในชุดและลบออกเมื่อเลือก ถ้าอย่างนั้นคุณจะไม่ไปถึงหมายเลขนี้อีกครั้งเมื่อสุ่มหรือไม่? สิ่งนี้แก้ปัญหาการทำซ้ำของตัวเลขสุ่มได้ดีมาก รหัสมีดังนี้:
โมฆะส่วนตัว removerandom (int start, int end, int count) {system.out.println ("อัลกอริทึมการกำจัดองค์ประกอบสุ่ม:"); StringBuffer buffer = new StringBuffer (); รายการ <จำนวนเต็ม> ตัวเลข = initList (เริ่มต้นจบ); สำหรับ (int i = 0; i <count; i ++) {int random = numberutils.randominteger (count - i); buffer.append (i == 0? ("[" + numbers.get (สุ่ม)): ("," + numbers.get (สุ่ม))); number.remove (สุ่ม); } buffer.append ("]"); System.out.println (บัฟเฟอร์); - ความพยายามครั้งที่สี่: อัลกอริทึมสุ่มถ่ายโอนของรัฐ
ในบล็อกก่อนหน้าของฉันหลายแห่งบางส่วนเป็นกระบวนการถ่ายโอนสถานะในอัลกอริทึม การถ่ายโอนสถานะเป็นหนึ่งในอัลกอริทึมที่ฉันโปรดปราน รูปที่ 1 ด้านล่างทำเครื่องหมายช่วงค่าของตัวเลขสุ่มและหมายเลขสีส้มในลำดับคือลำดับสุ่มในผลลัพธ์ มีลูกศรประบางส่วนในลำดับล่างซึ่งแสดงถึงการเปลี่ยนแปลงของสถานะ
รูปที่ 1 การสุ่มตัวอย่างอัลกอริทึมการสร้างตัวเลขแบบสุ่มขึ้นอยู่กับการเปลี่ยนแปลงสถานะ
รหัสการใช้งาน:
Void Private Void Statusrandom (int start, int สิ้นสุด, int count) {system.out.println ("อัลกอริทึมการถ่ายโอนสถานะสุ่ม:"); StringBuffer buffer = new StringBuffer (); int [] สถานะ = new int [end + 1]; สำหรับ (int i = 0; i <count; i ++) {int random = numberutils.randominteger (เริ่มต้นสิ้นสุด); System.err.println (สุ่ม); if (สถานะ [สุ่ม] == 0) {buffer.append (i == 0? ("[" + สุ่ม): ("," + สุ่ม)); สถานะ [สุ่ม] = สุ่ม == สิ้นสุด? เริ่มต้น: (สุ่ม + 1); // มันเป็นไปไม่ได้ที่จะมีหมายเลขก่อนเริ่ม} else {// // การถ่ายโอนสถานะ int index = random; ทำ {index = สถานะ [ดัชนี]; } ในขณะที่ (สถานะ [ดัชนี]! = 0); buffer.append (i == 0? ("[" + ดัชนี): ("," + ดัชนี)); สถานะ [ดัชนี] = ดัชนี == สิ้นสุด? เริ่มต้น: (ดัชนี + 1); // มันเป็นไปไม่ได้ที่จะมีตัวเลขก่อนเริ่ม}} buffer.append ("]"); System.out.println (บัฟเฟอร์); - ความพยายามครั้งที่ห้า: อัลกอริทึมสุ่มฟลอยด์แบบเรียกซ้ำ
อัลกอริทึมฟลอยด์ในที่สุดก็เป็นกระบวนการถ่ายโอนสถานะ อัลกอริทึมจะต้องมีรายการหรืออาร์เรย์เพื่อจัดเก็บหมายเลขสุ่มที่กำหนด ตามชื่อแนะนำฉันจะใช้โซลูชันแบบเรียกซ้ำที่นี่ ในกระบวนการเรียกซ้ำเราถ่ายโอนสถานะของหมายเลขสุ่ม I-th ไปยังหมายเลขสุ่ม I-1 รหัสมีดังนี้:
รายการส่วนตัว <Integer> SimpleFloyd (รายการ <จำนวนเต็ม>, จำนวน int, int start, int end) {ถ้า (count == 0) {return list; } list = simplefloyd (รายการ, นับ - 1, start, end - 1); int random = numberUtils.randominteger (เริ่มต้นสิ้นสุด); if (list.contains (สุ่ม)) {list.add (สิ้นสุด); } else {list.add (สุ่ม); } return list; - ความพยายามครั้งที่หก: วนซ้ำอัลกอริทึมแบบสุ่มของฟลอยด์
แนวคิดนี้คล้ายกับอัลกอริทึมแบบสุ่มฟลอยด์แบบเรียกซ้ำด้านบน แต่ที่นี่เราเพิ่มตัวแปรเพื่อปรับให้เหมาะสม ไม่จำเป็นต้องกลับมาอีกต่อไป รหัสมีดังนี้:
รายการส่วนตัว <Integer> iterationfloyd (int start, int end, int count) {system.out.println ("อัลกอริทึมสุ่มแบบฟลอยด์ซ้ำ:"); รายการ <จำนวนเต็ม> list = new ArrayList <> (); สำหรับ (int i = end - count+1; i <end; i ++) {int random = numberutils.randominteger (เริ่มต้น, i); if (list.contains (สุ่ม)) {list.add (i); } else {list.add (สุ่ม); }} รายการส่งคืน; - ผลการทดสอบ:
รูปที่ 2 ผลการทดสอบอัลกอริทึมการสร้างตัวเลขแบบสุ่ม
ในผลการทดสอบข้างต้นเราสามารถเห็นได้อย่างชัดเจนว่าอัลกอริทึมแบบสุ่มที่ไร้เดียงสาไม่เพียง แต่มีข้อมูลที่ซ้ำกัน แต่ยังใช้เวลานานที่สุด ดังนั้นหลีกเลี่ยงการใช้อัลกอริทึมนี้เมื่อสร้างตัวเลขสุ่มตัวอย่าง ในบรรดาอัลกอริทึมหลังอัลกอริทึมการถ่ายโอนสถานะเป็นสิ่งที่ดีที่สุดและอัลกอริทึมการสุ่มฟลอยด์ซ้ำเป็นครั้งที่สอง สิ่งนี้สามารถทำได้ตามความชอบส่วนตัว