Fisher Yates cổ điển trông như thế này:
void shuffle1(std::vector& vec)
{
int n = vec.size();
vì (int i = n - 1; i > 0; --i)
{
std::swap(vec[i], vec[Rand() % (i + 1)]);
}
}
Hôm qua tôi đã thực hiện sai phép lặp "ngược":
void shuffle2(std::vector& vec)
{
int n = vec.size();
vì (int i = 1; i < n; ++i)
{
std::swap(vec[i], vec[Rand() % (i + 1)]);
}
}
Phiên bản này tệ hơn (hoặc tốt hơn) so với phiên bản đầu tiên? Nó có làm sai lệch xác suất kết quả không?
Vâng, giả sử rand()
được phân bố đều. Chúng tôi sẽ chứng minh điều này bằng cách chỉ ra rằng mỗi đầu vào tạo ra mỗi hoán vị với xác suất bằng nhau.
N=2 rất dễ chứng minh. Chúng ta sẽ vẽ cái này dưới dạng cây, với các nút con biểu thị mỗi chuỗi bạn có thể nhận được bằng cách chèn ký tự sau dấu phẩy vào chuỗi ngoài cùng bên trái.
0,1 // đầu vào trong đó 0,1 đại diện cho các chỉ số
01 10 //output. Biểu thị các hoán vị của 01. Rõ ràng là mỗi hoán vị có xác suất bằng nhau
Đối với N, chúng ta sẽ có tất cả các hoán vị của N-1 và hoán đổi ngẫu nhiên ký tự cuối cùng của N
(N-1 hoán vị thứ 0),N..... (N-1 hoán vị thứ 1),N __________________
/ \ / \ \
Hoán vị thứ 0 của N Hoán vị thứ 1.... (I*N)hoán vị thứ ((I*N)+1)hoán vị thứ .... (I*N)+(I-1)hoán vị thứ
Cảm ứng kém này sẽ dẫn đến việc nó được phân bố đồng đều.
例子:
N=2:
0,1
01 10 // đây là những hoán vị. Mỗi hoán vị đều có xác suất bằng nhau.
N=3:
0,1|2 // | được sử dụng để phân tách các ký tự mà chúng ta sẽ chèn sau
01,2 10,2 // 01, 10 là hoán vị từ N-1, 2 là giá trị mới
210 021 012 201 120 102 // đây là các hoán vị, xác suất vẫn bằng nhau
N=4: (cong để hỗ trợ đọc)
0,1|23
01,2|3 10,2|3
012,3 021,3 210,3 102,3 120,3 201,3
0123 0132 0321 3230 2013 2031 2310 3012
0213 0231 0312 3210 1203 1230 1302 3201
2103 2130 2301 3102 1023 1032 1320 3021
等等
Tôi là một lập trình viên xuất sắc, rất giỏi!