[TIP]Kỹ thuật random, tạo danh sách (mảng) ngẫu nhiên trong java

JackV

Administrator
Staff member
Ở bài viết này JackV sẽ hướng dẫn các bạn 3 kỹ thuật random thường dùng:
1. Random tự nhiên, có thể lặp lại.
2. Random có thể lặp lại nhưng 2 phần tử liên tiếp không trùng nhau.
3. Random không lặp lại.

Các bạn có thể random các phần tử trong một danh sách theo cách này, ở đây mình sẽ làm trường hợp đơn giản nhất có thể ứng dụng cho những trường hợp random danh sách.

Mình sẽ thực hiện random một dãy 10 số int, xem như random index của một danh sách khoảng 100 phần tử..

Sau khi khởi tạo
PHP:
        Random rd = new Random();
1. Random tự nhiên, có thể lặp lại
Bạn sẽ sử dụng rd.nextInt(100); trong trường hợp này thì các số cho kết quả sẽ nằm từ 0-99.

2. Để random tự nhiên có thể lặp lại nhưng hai phần tử liền kề không trùng nhau.
Đơn giản là ta dùng một biến tạm để lưu giá trị random lần trước, khi random ra một giá trị mới thì kiểm tra, nếu giá trị mới khác giá trị cũ thì sử dụng rồi biến tạm set giá trị bằng giá trị mới.

3. Random không lặp lại.
Trong trường hợp này sử dụng một Vector, ta sẽ ứng dụng phương thức kiểm tra có chứa object hay không của vector v.contains(iNew) kết quả false thì chúng ta add thêm vào, cuối cùng ta có vector chứa các số không trùng nhau.

Demo
PHP:
import java.util.Random;
import java.util.Vector;

/**
 *
 * @author Thanh Nhan <JackV at congdongjava.com>
 */
public class HowToRandom {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Random rd = new Random();

        //random 10 number bettween 100
        System.out.println("random 10 number bettween 100");
        for (int i = 0; i < 10; i++) {
            System.out.println("Item " + (i+1) + ":" + rd.nextInt(100));
        }
       
        //random new item difference from previous random item
        int iNewNumber = 0, iPrevious = -1;
        for (int i = 0; i < 10; ) {
            iNewNumber = rd.nextInt(100);
            if (iNewNumber != iPrevious){
                i++;
                iPrevious = iNewNumber;
                System.out.println("Item " + (i+1) + ":" + iNewNumber);
            }
        }
       
        //random 10 unique number
        Vector v = new Vector();
        int iNew = 0;
        for (int i = 0; i < 10;  ) {
            iNew = rd.nextInt(100);
            if (!v.contains(iNew)){
                i++;
                v.add(iNew);
                System.out.println("Item " + (i+1) + ":" + iNew);
            }
        }
    }
}
 
Sửa lần cuối:

monday0rsunday

Active Member
21/10/11
512
93
28
Ðề: [TIP]Kỹ thuật random

Mình xin góp thêm mở rộng cho 2) (thu nhỏ từ 3) là: random , nhưng ít nhất sau 1 số lần mới cho phép có khả năng bị trùng.
Code:
        Random rd = new Random();
        Vector v = new Vector();
        int maxNumberOccur = 3;
        int iNewNumber = 0;
        for (int i = 0; i < 10; i++) {
            do{
                iNewNumber = rd.nextInt(100);
            }while(v.contains(iNewNumber));
            if(!v.isEmpty()&&v.size()>=maxNumberOccur) v.remove(0);
            v.add(iNewNumber);
            System.out.println("Item " + (i+1) + ":" + iNewNumber);
        }
 

JackV

Administrator
Staff member
Ðề: [TIP]Kỹ thuật random

Việc random thì trùng nhau là điều không tránh khỏi đối với kích thước nhỏ, mà bỏ tính chất này đi thì chả khác gì ko random.
Sao bạn lại nói là bỏ tính trùng nhau đi xem như không random?

Hãy chọn ngẫu nhiên 3 trong 5 người có mặt sớm nhất phỏng vấn lần 1.
ngẫu nhiên > Random
3 trong 5 người > Không trùng.
>>> Chọn ngẫu nhiên nhưng không được chọn lại phần tử đã chọn. Vụ này dùng vector, cái nào chọn rồi thì remove sẽ đơn giản.
 

monday0rsunday

Active Member
21/10/11
512
93
28
Ðề: [TIP]Kỹ thuật random

Sao bạn lại nói là bỏ tính trùng nhau đi xem như không random?

Hãy chọn ngẫu nhiên 3 trong 5 người có mặt sớm nhất phỏng vấn lần 1.
ngẫu nhiên > Random
3 trong 10 người > Không trùng.
>>> Chọn ngẫu nhiên nhưng không được chọn lại phần tử đã chọn. Vụ này dùng vector, cái nào chọn rồi thì remove sẽ đơn giản.
Sr. Mình sẽ đính chính lại. :D
 

hongtamtk

Member
22/1/12
115
7
18
30
me.zing.vn
Ðề: [TIP]Kỹ thuật random

Sao mình sử dụng hàm Random ko dc, mình thấy các bạn import java.util.Random;
nhưng mình dùng netbeans ko có cái này nó vẫn bình thường và dùng rd.nextInt(100) ko dc hepl với.
 

monday0rsunday

Active Member
21/10/11
512
93
28
Ðề: [TIP]Kỹ thuật random

Sao mình sử dụng hàm Random ko dc, mình thấy các bạn import java.util.Random;
nhưng mình dùng netbeans ko có cái này nó vẫn bình thường và dùng rd.nextInt(100) ko dc hepl với.
Chuyện có lỗi mà IDE ko báo ko phải là chuyện ko thể xảy ra. Có lần tớ còn bị nó báo lỗi mà ko hiểu lỗi ở đâu (chỉ có mở lại mà có lỗi) =.=".
Có thể jdk/jre của bạn có lỗi ko chứa gói java.util, hoặc gì gì đó:D
Ps:
có 2 cách gọi random, 1 là dùng java.util.Random, 2 là dùng java.lang.Math
java.util.Random thì cho phép nhiều lựa chọn hơn (nguyên, thực, giữa 1 khoảng...)
Còn Math thì chỉ có 1: giữa 0.0 và 1.0 (gọi method static Math.random()). Đơn giản bạn có thể dùng (int)(Math.random()*100) để thay thế, nếu ko xử lí đc lỗi.
 

thuyloanoi

New Member
27/4/12
5
0
1
30
TPHCM
Lần trước phỏng vấn có câu code Random này mà ko làm đc. Giờ thì hiểu rùi, thanks chủ topic nhé ^.^
 

Gemini Tran

New Member
25/6/12
18
4
3
32
Mình muốn mở rộng topic này ở khía cạnh: tạo random 1 phần tử sao cho không trùng lặp từ 1 thư viên phần tử, cho rằng thư viện này chứa số phần tử rất lớn (hàng triệu trở lên). Vậy hướng tiếp cận thế nào để tối ưu?
VD: cần tạo 1 phần tử mới, có dạng thế này: aI82ZltwE sao cho phần tử mới tạo ra không được trùng với bất kỳ phần tử nào trong một tập hợp các phần tử đồng dạng với phần tử cần tạo. Mỗi phần tử có độ dài là 9, được tạo ra bằng cách random các ký tự (a-z, A-Z, 0-9).
 

JackV

Administrator
Staff member
tạo random 1 phần tử sao cho không trùng lặp từ 1 thư viên phần tử
Lấy ra hay là tạo ra vậy bạn, 2 cái khác nhau à nha. Ra đề như vậy không có ví dụ kèm theo thì có nhiều cách hiểu lắm đó bạn.
VD: cần tạo 1 phần tử mới, có dạng thế này: aI82ZltwE sao cho phần tử mới tạo ra không được trùng với bất kỳ phần tử nào trong một tập hợp các phần tử đồng dạng với phần tử cần tạo. Mỗi phần tử có độ dài là 9, được tạo ra bằng cách random các ký tự (a-z, A-Z, 0-9).
Đề này có vấn đề lớn ẩn dấu trong nó đây, nếu tập hợp đó đã lớn rồi mà phần tử tạo ra có 9 ký tự không theo cấu trúc (ví dụ AABBCCDDE AA là số, BB là chữ, ...) nào cả thì phần kiểm tra sẽ rất là hao tốn xử lý, để kiểm tra có thể dùng database nhưng khi không có cấu trúc có thể sẽ phải random số lượng rất lớn mới tìm ra được phần tử không trùng với phần tử nào của thư viện.
 

Gemini Tran

New Member
25/6/12
18
4
3
32
@JackV: yêu cầu là tạo mới, anh :D
Với bài toán này thì mình cần phải đưa ra giải pháp lưu trữ cũng như cấu trúc của phần tử để thực hiện tạo & truy xuất hiệu quả nữa :D
 

Nancru

CongDongJava Project Leader
Staff member
9/10/11
1,642
309
83
cái đoạn random này giống của mediafire nhỉ. Thường thì để lấy một unique key thì mình thấy lấy thời gian hiện tại tính bằng nano giây băm ra hoặc mã hóa, như vậy ko cần quay lại db để check unique cũng đc
 

JackV

Administrator
Staff member
@JackV: yêu cầu là tạo mới, anh :D
Với bài toán này thì mình cần phải đưa ra giải pháp lưu trữ cũng như cấu trúc của phần tử để thực hiện tạo & truy xuất hiệu quả nữa :D
[TIP]Kỹ thuật random
Đây là một bài hướng dẫn, bạn hiện thực vấn đề để mọi người mở rộng đi.
Bạn có thể tạo một chủ đề mới [TIP]Kỹ thuật random nâng cao và hiện thực hướng dẫn của bạn cho mọi người trao đổi nhé.
 
  • Like
Reactions: Tannd

nhohb2011

Active Member
29/12/11
104
52
28
Quận 9, TP.HCM
www.shopwebre.com
Đóng góp thêm 1 kỹ thuật ramdom không trùng với mảng cho trước, dùng Collections.shuffle.

Đầu tiên ta phải khởi tạo 1 danh sách:
Code:
java.util.List<Integer> arrayList = new ArrayList();
Thêm 100 phần tử vào danh sách:
Code:
for(int i = 0; i < 100; i++){
        arrayList.add(i + 1);
}
Sau đó dùng Collections.shuffle để xáo trộn danh sách này, ta sẽ được 1 danh sách mới với các phần tử đã bị xáo trộn.


Code:
java.util.Collections.shuffle(arrayList);
DEMO:
Code:
import java.util.ArrayList;
import java.util.Arrays;

/**
* @author  : huynhnguyen.it@gmail.com
* @project : AdsPoster
* @document: Collections.java
* @created : Sep 20, 2013 12:43:45 PM
*/
public class Collections {
    public static void main(String[]a){
        java.util.List<Integer> arrayList = new ArrayList();

        for(int i = 0; i < 100; i++){
            arrayList.add(i + 1);
        }

        java.util.Collections.shuffle(arrayList);

        for(int i = 0; i < arrayList.size(); i++){
            System.out.print(arrayList.get(i) + " ");
        }
    }
}
 

Nhoc con PTIT

Member
15/7/13
49
2
8
26
Bạn nêu vấn đề cần phải rõ ràng hơn. Nêu vấn đề không có code như vậy thì chỉ có thể đoán mò, bạn tự đoán đi.
Code:
public class NewClass {
    public static void main(String[] args) {
        int[] a=new int [5];
        Random ran=new Random();
        a[0]= ran.nextInt()%5+1;
        int b,j;
        for(int i=1;i<5;i++){
            Try:
            b=ran.nextInt()%5+1;
            for(j=i-1;j>=0;j--)
                  if(a[j]==b)  {GOTO Try;}
            a[i]=b;
        }
        for(int i=0;i<5;i++)
            System.out.println(a[i]+"  ");
    }
}
Đây bác ak
 

SITUVN

Well-Known Member
25/2/12
965
262
63
Bạn dùng goto được à? Mình dùng không được.
Thử trên http://www.compileonline.com/compile_java_online.php thì nó chạy không được (JDK, JRE 1.7), mình phải sửa thành continue.
goto trong java tuy là một từ khóa nhưng chưa có chức năng, thay vào đó có thể dùng break và continue thay cho nó. Trên StackOverflow cũng nói thế.

Kết quả sau khi sửa:
PHP:
import java.util.Random;

public class NewClass {
    public static void main(String[] args) {
        int[] a = new int [5];
        Random ran = new Random();
        int b,j;
        Out:
        for(int i = 0; i < 5; i++){
            b = Math.abs(ran.nextInt() % 5) + 1;
            System.out.println(i + ": " + b);
            for(j = 0; j < i; j++) {
                  if(a[j] == b) {
                    i--;
                    continue Out;
                  }
            }
            System.out.println(i + ": " + b + " OK!");
            a[i] = b;
        }
        System.out.println("Result: ");
        for(int i = 0; i < 5; i++)
            System.out.print(a[i] + "  ");
    }
}
Kết quả ngẫu nhiên:
Code:
0: 3
0: 3 OK!
1: 1
1: 1 OK!
2: 1
2: 4
2: 4 OK!
3: 3
3: 5
3: 5 OK!
4: 4
4: 2
4: 2 OK!
Result:
3  1  4  5  2
 

SITUVN

Well-Known Member
25/2/12
965
262
63
Cách làm ngẫu nhiên của bạn thấy hay phết. Ngẫu nhiên từ 1 đến n, mà không số nào "đụng hàng" nhau :)). Giống như là xáo trộn vị trí.

Sửa tí cho nó "cơ động" 1 tí:
PHP:
import java.util.Random;

public class NewClass {
    public static int[] Shuffle(int n) {
        int[] a = new int [n];
        Random ran = new Random();
        int i = 0, j, b;
        boolean isDuplicated = false;
      while (i < a.length) {
            // Dùng Math.abs() để tráng số âm và 0
            b = Math.abs(ran.nextInt() % a.length) + 1;
            System.out.println("Index: " + i + ", Number: " + b);
            isDuplicated = false;
            // Có thể tách thành 1 phương thức riêng
            for(j = 0; j < i; j++) {
                  if(a[j] == b) {
                    isDuplicated = true;
                  }
            }
            // Nếu không trùng thì gán và tăng i
            if (!isDuplicated) {
                System.out.println("OK!");
                a[i] = b;
                i++;
            }
            // Nếu trùng thì tếp tục "dò số"
        }
        System.out.println("\r\nResult: ");
        for(i = 0; i < a.length; i++) {
            System.out.print(a[i] + "  ");
        }
        return a;
    }
    public static void main(String[] args) {
        Shuffle(20);
    }
}
Kết quả ngẫu nhiên:
Code:
Index: 0, Number: 15
OK!
Index: 1, Number: 20
OK!
Index: 2, Number: 18
OK!
Index: 3, Number: 12
OK!
Index: 4, Number: 5
OK!
Index: 5, Number: 20
Index: 5, Number: 16
OK!
Index: 6, Number: 15
Index: 6, Number: 17
OK!
Index: 7, Number: 12
Index: 7, Number: 10
OK!
Index: 8, Number: 17
Index: 8, Number: 12
Index: 8, Number: 8
OK!
Index: 9, Number: 12
Index: 9, Number: 15
Index: 9, Number: 3
OK!
Index: 10, Number: 9
OK!
Index: 11, Number: 19
OK!
Index: 12, Number: 11
OK!
Index: 13, Number: 2
OK!
Index: 14, Number: 9
Index: 14, Number: 3
Index: 14, Number: 12
Index: 14, Number: 12
Index: 14, Number: 7
OK!
Index: 15, Number: 18
Index: 15, Number: 2
Index: 15, Number: 4
OK!
Index: 16, Number: 8
Index: 16, Number: 13
OK!
Index: 17, Number: 12
Index: 17, Number: 2
Index: 17, Number: 5
Index: 17, Number: 20
Index: 17, Number: 9
Index: 17, Number: 16
Index: 17, Number: 20
Index: 17, Number: 10
Index: 17, Number: 14
OK!
Index: 18, Number: 20
Index: 18, Number: 15
Index: 18, Number: 11
Index: 18, Number: 19
Index: 18, Number: 13
Index: 18, Number: 14
Index: 18, Number: 17
Index: 18, Number: 16
Index: 18, Number: 9
Index: 18, Number: 5
Index: 18, Number: 2
Index: 18, Number: 18
Index: 18, Number: 11
Index: 18, Number: 12
Index: 18, Number: 1
OK!
Index: 19, Number: 12
Index: 19, Number: 9
Index: 19, Number: 18
Index: 19, Number: 18
Index: 19, Number: 7
Index: 19, Number: 13
Index: 19, Number: 15
Index: 19, Number: 20
Index: 19, Number: 12
Index: 19, Number: 9
Index: 19, Number: 14
Index: 19, Number: 12
Index: 19, Number: 18
Index: 19, Number: 6
OK!

Result:
15  20  18  12  5  16  17  10  8  3  9  19  11  2  7  4  13  14  1  6
Càng về cuối và số lượng càng nhiều thì càng lâu. Nên cách này chưa hiệu quả nhất

Mới hồi hôm viết một bài về chọn ngẫu nhiên theo phần trăm bên http://CongDongCViet.com giờ lại ngẫu nhiên bên này, đoạn mã ngẫu nhiên thấy na ná nhau =)).

Cơn bản là rảnh:
PHP:
import java.util.Random;
import java.security.InvalidParameterException;

public class RandomTest {

    public static int[] Shuffle(int begin, int end) throws InvalidParameterException {
        return Shuffle(begin, end, end - begin + 1);
    }

    public static int[] Shuffle(int begin, int end, int shuffleTimes) throws InvalidParameterException {
        if (end - begin <= 1 || shuffleTimes < 1) throw new InvalidParameterException("Numer of element and shuffle times must larger than 1!");
        int[] r = new int[end - begin + 1];
        int i, j, a, b, t;
        Random ran = new Random();
        for (i = 0, j = begin; i < r.length; i++, j++) {
            r[i] = j;
        }
        //
        for (i = 0; i < shuffleTimes; i++) {
            a = Math.abs(ran.nextInt(r.length));
            b = Math.abs(ran.nextInt(r.length));
            if (a != b) {
                t = r[a];
                r[a] = r[b];
                r[b] = t;
            }
        }
        return r;
    }
    public static void main(String[] args) {
        if (args.length > 1) {
            try {
                int[] result;
                if (args.length == 2)
                result = Shuffle(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
                else
                result = Shuffle(Integer.parseInt(args[0]), Integer.parseInt(args[1]), Integer.parseInt(args[2]));
                for (int i = 0; i < result.length; i++) {
                   System.out.print(result[i] + " ");
                }
                System.out.println("\r\n" + result.length);
            } catch(InvalidParameterException ex) {
                System.out.println(ex.getMessage());
            } catch (Exception ex) {
                System.out.println("An error has occured: " + ex.getMessage());
            }
        } else {
            System.out.println("Usage: RandomTest BeginNumber EndNumber [ShuffleTime]");
        }
    }
}
 

Joe

Thành viên VIP
21/1/13
2,969
1,310
113
Bạn dùng goto được à? Mình dùng không được.
=)) By the way, I got an idea:
PHP:
        HashMap hm = new HashMap();
        for(int i = 0; i < 5; i++){
            b = Math.abs(ran.nextInt() % 5) + 1;
            System.out.println(i + ": " + b);
            if (hm.put(b+"", b) == null) {
                System.out.println(i + ": " + b + " OK!");
                a[i] = b;
            } else --i;
It does not look "sophisticated" but it requires neither the 2nd loop nor the GOTO/continue.