Bắt đầu từ trích dẫn này của Skeet:
Đó không phải là một cách xáo trộn mà tôi thích, chủ yếu là với lý do đó là O (n log n) không có lý do chính đáng khi dễ dàng thực hiện xáo trộn O (n). Mã trong câu hỏi "hoạt động" bằng cách cơ bản đưa ra một số ngẫu nhiên ( hy vọng là duy nhất! ) Cho mỗi phần tử, sau đó sắp xếp các phần tử theo số đó.
Tôi sẽ tiếp tục giải thích một chút về lý do cho sự độc đáo hy vọng!
Bây giờ, từ Enumerable.OrderBy :
Phương pháp này thực hiện một loại ổn định; nghĩa là, nếu các khóa của hai phần tử bằng nhau, thứ tự của các phần tử được giữ nguyên
Cái này rất quan trọng! Điều gì xảy ra nếu hai phần tử "nhận" cùng một số ngẫu nhiên? Nó xảy ra rằng họ vẫn theo thứ tự như họ đang ở trong mảng. Bây giờ, khả năng cho điều này xảy ra là gì? Thật khó để tính toán chính xác, nhưng có vấn đề sinh nhật chính xác là vấn đề này.
Bây giờ, nó có thật không? Có đúng không
Như mọi khi, khi nghi ngờ, hãy viết một số dòng chương trình: http://pastebin.com/5CDnUxPG
Khối mã nhỏ này xáo trộn một mảng gồm 3 phần tử một số lần nhất định bằng thuật toán Fisher-Yates được thực hiện ngược, thuật toán Fisher-Yates được thực hiện về phía trước (trong trang wiki có hai thuật toán mã giả ... Chúng tạo ra tương đương kết quả, nhưng một kết quả được thực hiện từ phần tử đầu tiên đến phần tử cuối cùng, trong khi phần tử kia được thực hiện từ phần tử cuối cùng đến phần tử đầu tiên), thuật toán sai ngây thơ của http://blog.codinghorror.com/the-danger-of-naivete/ và sử dụng .OrderBy(x => r.Next())
và .OrderBy(x => r.Next(someValue))
.
Bây giờ, Random. Tiếp theo là
Số nguyên có chữ ký 32 bit lớn hơn hoặc bằng 0 và nhỏ hơn MaxValue.
vậy nó tương đương với
OrderBy(x => r.Next(int.MaxValue))
Để kiểm tra xem sự cố này có tồn tại hay không, chúng ta có thể phóng to mảng (một thứ rất chậm) hoặc đơn giản là giảm giá trị tối đa của trình tạo số ngẫu nhiên ( int.MaxValue
không phải là số "đặc biệt" ... Đây đơn giản là một số rất lớn). Cuối cùng, nếu thuật toán không bị sai lệch bởi tính ổn định của OrderBy
, thì bất kỳ phạm vi giá trị nào cũng sẽ cho kết quả tương tự.
Chương trình sau đó kiểm tra một số giá trị, trong phạm vi 1 ... 4096. Nhìn vào kết quả, khá rõ ràng rằng với các giá trị thấp (<128), thuật toán rất sai lệch (4-8%). Với 3 giá trị bạn cần ít nhất r.Next(1024)
. Nếu bạn làm cho mảng lớn hơn (4 hoặc 5), thì thậm chí r.Next(1024)
là không đủ. Tôi không phải là chuyên gia về xáo trộn và toán học, nhưng tôi nghĩ rằng với mỗi bit dài thêm của mảng, bạn cần thêm 2 bit có giá trị tối đa (vì nghịch lý sinh nhật được kết nối với sqrt (chữ số)), vì vậy rằng nếu giá trị tối đa là 2 ^ 31, tôi sẽ nói rằng bạn sẽ có thể sắp xếp các mảng tối đa 2 ^ 12/2 ^ 13 bit (4096-8192 phần tử)