1,緣起
最近工作上遇到一個問題,即將一組數據,比如[A,B,C,D,E]其中的兩個B,E按隨機排列,其他的仍在原來的位置:
原始數組:[A,B,C,D,E]
隨機字母:[B,D]
可能結果:[A,B,C,D,E],[A,D,C,B,E]
在解決這個問題的過程中,需要解決的一個問題是,怎么樣讓一個數組隨機排序?上網一查,這也是計算機科學基礎問題,也稱之為洗牌算法(Shuffle Algorithm)。
2,問題及解決
2.1,問題
很簡單:給定一個數組,將其中的元素隨機排列。比如給定數組arry=>[1,2,3,4,5]。有A5-5種結果即5!=120種結果
2.2,解決
也很簡單,如果用白話來說就是:
a,選中第1個元素,將其與n個元素中的任意一個交換(包括第1個元素自己)。這時排序后的第1個元素已經確定。
b,選中第2個元素,將其與n-1個元素中作任意一個交換(包括第2個元素自己)。
c,重復上面步驟,直到剩1個元素為止。
3.3,代碼
知道其算法了,實現就簡單了:
/// <summary> /// Randomize the list elements using Fisher–Yates shuffle algorithm http://en.wikipedia.org/wiki/Fisher-Yates_shuffle /// </summary> /// <typeparam name="T">elements type</typeparam> /// <param name="list"></param> public static void Shuffle<T>(this IList<T> list) { Random rng = new Random(); int n = list.Count; while (n > 1) { n--; int k = rng.Next(n + 1); T value = list[k]; list[k] = list[n]; list[n] = value; } }
3.4,其它
該算法復雜度為O(n),且無偏差,各個元素隨機概率相等。確實是一個好算法:)。
在Wiki上,還有一些該算法的變種,但還是上面講的那種比較好用,最初的Fisher–Yates算法並不好用,復雜度為O(n^2)。
參考: