Làm thế nào để random 1 mảng a[] n phần tử từ 1 mảng b[] m phần tử có sẵn với số phần tử khá lớn mà không bị trùng lặp
Hello
Mình đang cần tạo 1 mảng ngẫu nhiên a[] có n phần tử từ 1 mảng b[] m phần tử có sẵn ( m>n và a[i] # a[j])
Ví dụ cần random 3 phần tử từ mảng [1,2,3,4,5,6,7,8,9]
a[1] # a[2] # a[3]
Và nếu như mình random 1 mảng x[] m phần tử từ 1 dãy số nằm trong khoảng [a,b] như thế này thì liệu các x[i] có bị lặp không.
srand(time(NULL));
for (unsigned int i = 0; i < m; i++) {
testSample[i] = a + rand()%(b-a+1);
}
Và số phần tử mình cần random có thể lên đến vài nghìn thì có nên dùng không, cách này random dựa vào thời gian, mình không biết có nguy cơ trùng phần tử không và mỗi lần random chạy 1 lần a + rand()%(b-a+1). Cần random vài nghìn phần tử chắc chết
Thank you
C++ thì xài
<random>
ấy. random kiểu trên trùng là đương nhiên. Muốn các phần tử ko trùng nhau kiểu nào? n phần tử có giá trị 1,2,3,…,n hay là n phần tử có giá trị bất kì? Nếu là kiểu 1,2.3,…,n thì tạo 1 mảng chứa n giá trị rồi shuffle mảng đó là xong, còn n phần tử giá trị bất kì thì phải xài 1 cái set để loại phần tử trùng nhau, xàistd::set<int>
hoặcstd::unordered_set<int>
“random dựa vào thời gian” nghĩa là sao @_@ Chỉ có seed là dựa vào thời gian thôi mà random bằng rand() đâu có liên quan gì tới thời gian. C++ ko có pseudo random bit generator nào “an toàn” cho mật mã hết (CSPRNG), nhưng xài MSVC 2017 thì có
std::random_device
được “nổ” là CSPRNG.Cái này em có đọc bài của anh trên diễn đàn rồi. Nhưng kiểu em muốn là có 100 ảnh được đánh số từ 1->100. Cần chọn ra 20 ảnh chẳng hạn. 20 ảnh này được lấy ra từ 100 ảnh và 20 ảnh này không được trùng nhau
Vì số phần tử khá lớn, ví dụ 5000 ngìn ảnh, cần lấy ra 1500 ảnh mà random dựa vào hàm thời gian rồi viết 1 hàm kiểm tra sự trùng lặp thì hơi lâu
cách dễ nhất vẫn là shuffle hết 100 số đó rồi lấy 20 số đầu tiên trong mảng đã shuffle.
việc xáo trọn đó có ngẫu nhiên không anh
có chứ sao ko @_@
tạo 1 cái random engine, rồi đẩy nó vào
std::shuffle
trong<algorithm>
cách “khó” hơn 1 chút là xài reservoir sampling
E thây xóa trộn mảng vẫn dùng hàm rand dựa vào thời gian
STDIO
Nhưng chắc mỗi lần lấy phần tử xong bỏ phần đó đi thì sẽ k trùng lặp được là ổn rồi
Xáo Trộn Một Mảng Cho Trước :: Bài viết :: STDIO
Bài viết hướng dẫn độc giả, đặc biệt là những độc giả mới bắt đầu làm quen với lập trình hình thành tư duy phân tích và thiết kế một thuật toán xáo trộn 1 mảng cho trước.
bài trang này nó để
srand(time(NULL));
ở trong cái hàm kia thì tác giả viết chưa đúng rồi ~.~chưa kể cách xài srand sai, C++ hiện đại ko ai xài
rand()
nữa hết. Google "rand() Considered Harmful " là thấy.ko có cái gọi là dùng hàm rand dựa vào thời gian, seed hàm rand dựa vào thời gian
tác giả bài đó chắc chưa nghe nói tới
std::random_shuffle
có sẵn trong<algorithm>
nên mới khổ dâm viết 1 cái hàm shuffle mà viết cũng sai nữa ~.~ (để srand ở trong). Nhưng C++14 đã đánh dấurandom_shuffle
là lỗi thời rồi, và C++17 đã xóa sổ nó ra khỏi thư viện chuẩn vì ko ai khuyến khích xài rand() nữa cả. Sở dĩ nó còn là vì C++ phải chạy code C được.http://en.cppreference.com/w/cpp/algorithm/sample
C++17 có sẵn hàm
sample
luôn nè, khỏi cần khổ dâm viết hàm riêngThuật toán viết bằng C#:
2 cách đơn giản này ổn không anh nhẩy
sao ko xài
std::shuffle
1 dòng @_@, còn là sinh viên năm 1 hay sao mà ko dám xài hàm trong thư viện chuẩnEm làm như thế nàyy ổn không anh nhẩy. E đang rảnh rảnh nên xem có cách nào đơn giản code được hem
xóa cái srand. Mà thôi code xài rand ko thèm đọc @_@
Để em tìm hiểu xem tại sao không nên dùng rand. Giờ mới biết :3
dễ lắm, chạy code này trên VC++ là thấy @_@
nó in ra 18% chứ ko phải 15%
Nếu mảng b[] không hằng thì chỉ cần n thao tác Fisher-Yates trên b rồi copy phần đầu qua a[].
Nếu b là hằng thì phải chọn và thay thế, O(m).
Hai trường hợp đều là O(1) mem.