1. 程式人生 > >javascript隨機打亂陣列shuffle

javascript隨機打亂陣列shuffle

javascript 沒有為我們提供shuffle打亂陣列的函式,那日常開發是怎樣實現隨機打亂陣列呢

一.使用sort方法?

藉助 sort 方法不是真正意義上的完全亂序

原因:

在Chrome v8引擎原始碼中,處理 sort 方法時,使用了插入排序和快排兩種方案。當目標陣列長度小於10時,使用插入排序;反之,使用快排。

其實不管用什麼排序方法,大多數排序演算法的時間複雜度介於 O(n) 到 O(n2) 之間,元素之間的比較次數通常情況下要遠小於 n(n-1)/2,也就意味著有一些元素之間根本就沒機會相比較(也就沒有了隨機交換的可能),這些 sort 隨機排序的演算法自然也不能真正隨機。

通俗的說,其實我們使用 array.sort 進行亂序,理想的方案或者說純亂序的方案是:陣列中每兩個元素都要進行比較,這個比較有 50% 的交換位置概率。如此一來,總共比較次數一定為 n(n-1)。

而在 sort 排序演算法中,大多數情況都不會滿足這樣的條件。因而當然不是完全隨機的結果了。


某些場景下,這樣的方法可以使用。但是這不是真正意義上的完全亂序,一些需求中(比如抽獎)這樣的寫法會出大問題。
 

var arr = ['A','B','C','D','F'];
var brr = [1,2,3,4,5,6,7,8];

var arr1 = arr.sort(function() {
    return .5 - Math.random();
});
var brr1 = brr.sort(function() {
    return .5 - Math.random();
});
console.log(arr1);
console.log(brr1);

二.Fisher–Yates shuffle 洗牌演算法

Fisher–Yates shuffle 洗牌演算法可以做到理論上的完全亂序

lodash.js 中的 shuffle 函式也使用此演算法實現

function shuffleSelf(array, size) {
        var index = -1,
            length = array.length,
            lastIndex = length - 1;

        size = size === undefined ? length : size;
        while (++index < size) {
            // var rand = baseRandom(index, lastIndex),
            var rand = index + Math.floor( Math.random() * (lastIndex - index + 1))
                value = array[rand];

            array[rand] = array[index];

            array[index] = value;
        }
        array.length = size;
        return array;
    }

參考連結:

https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle 

https://raw.githubusercontent.com/lodash/lodash/4.17.5/dist/lodash.js