Bạn đang tìm kiếm một derangement các mục của bạn.
Trước hết, thuật toán của bạn hoạt động theo nghĩa là nó tạo ra một sự xáo trộn ngẫu nhiên, nghĩa là một hoán vị không có điểm cố định. Tuy nhiên nó có một lỗ hổng rất lớn (mà bạn có thể không nhớ, nhưng đáng lưu ý): một số chuyển động không thể có được với thuật toán của bạn. Nói cách khác, nó đưa ra xác suất bằng không cho một số sai lệch có thể xảy ra, do đó phân phối kết quả chắc chắn không phải ngẫu nhiên thống nhất.
Một giải pháp khả thi, như đề xuất trong các ý kiến, sẽ được sử dụng một thuật toán từ chối:
- chọn một hoán vị đồng đều một cách ngẫu nhiên
- nếu nó HAX không có điểm cố định, trả lại
- khác thử lại
Có nghĩa là xác suất có được sự xáo trộn gần 1/e
= 0.3679 (như đã thấy trong bài viết wikipedia). Điều đó có nghĩa là để có được sự xáo trộn, bạn sẽ cần tạo ra mức trung bình là e
= 2.718 hoán vị, điều này khá tốn kém.
Cách tốt hơn để làm điều đó là từ chối ở mỗi bước của thuật toán. Trong giả, một cái gì đó như thế này (giả sử mảng ban đầu chứa i
ở vị trí i
, tức là a[i]==i
):
for (i = 1 to n-1) {
do {
j = rand(i, n) // random integer from i to n inclusive
} while a[j] != i // rejection part
swap a[i] a[j]
}
Sự khác biệt chính từ thuật toán của bạn là chúng ta cho phép j
được bằng i
, nhưng chỉ khi nó không tạo ra một điểm cố định. Nó hơi dài hơn để thực thi (do phần từ chối) và yêu cầu bạn có thể kiểm tra xem mục nhập có ở vị trí ban đầu hay không, nhưng có lợi thế là nó có thể tạo ra mọi sự xáo trộn có thể (thống nhất, cho rằng vấn đề).
Tôi đoán các thuật toán không từ chối nên tồn tại, nhưng tôi tin rằng chúng sẽ kém thẳng về phía trước.
Edit:
thuật toán của tôi là thực sự xấu: bạn vẫn có cơ hội kết thúc với điểm cuối cùng unshuffled, và sự phân bố không phải là ngẫu nhiên ở tất cả, nhìn thấy sự phân bố biên của một mô phỏng:
Thuật toán tạo ra các biến dạng phân bố thống nhất có thể được tìm thấy here, với một số ngữ cảnh về vấn đề, giải thích và phân tích kỹ lưỡng.
Sửa Thứ hai:
Thực ra thuật toán của bạn được gọi là Sattolo's algorithm, và được biết đến để sản xuất tất cả các chu kỳ với xác suất bằng nhau. Vì vậy, bất kỳ derangement mà không phải là một chu kỳ nhưng một sản phẩm của một số chu kỳ disjoint không thể thu được với các thuật toán. Ví dụ, với bốn yếu tố, hoán vị trao đổi 1 và 2, và 3 và 4 là một sự xáo trộn nhưng không phải là một chu kỳ.
Nếu bạn không nhớ chỉ có chu kỳ, thuật toán của Sattolo là con đường để đi, nó thực sự nhanh hơn nhiều so với thuật toán derangement thống nhất, vì không cần từ chối.
Đặt từng mục ở vị trí khác một cách ngẫu nhiên. Có một cơ hội nhỏ mà bạn không thể tìm thấy một vị trí cho người cuối cùng nhưng sau đó chỉ cần bắt đầu lại. – adrianm
https://en.wikipedia.org/wiki/Sattolo's_algorithm – Bergi
Một tái hữu hạn sẽ chứng minh về mặt toán học rằng thuật toán của bạn hoạt động: ở phần cuối của lặp i, các phần tử ở vị trí i không phải là yếu tố ban đầu nữa. Khi ở bước lặp lại n-2, dữ liệu [n-2] được tự động xáo trộn với dữ liệu [n-1]. Do đó, nếu dữ liệu [n-1] vẫn giữ giá trị ban đầu của nó, nó sẽ được hoán đổi ở lần lặp cuối cùng. Cũng vậy với dữ liệu [n-1]. – Rerito