JavaScript tips —— 談談陣列亂序

nanchenk發表於2018-01-24

JavaScript tips —— 談談陣列亂序

前言

先看一個段程式碼

function randArr (arr) {
    return arr.sort(() => {
        return (Math.random() - 0.5);
    });
}複製程式碼

目的是為了實現給定陣列的亂序。

利用陣列的sort方法,判斷隨機出來的0~1的值與0.5的大小,實現偽排序。

為什麼說是偽排序呢?程式碼的邏輯沒毛病啊。

對,從這個層面來看,簡單明瞭,完美的實現了需求,本著凡事往祖墳刨得精神。來看看這段程式碼的內部實現。

瀏覽器實現

ECMA Script

The elements of this array are sorted. The sort is not necessarily stable (that is, elements that compare equal do not necessarily remain in their original order). If comparefn is not undefined, it should be a function that accepts two arguments x and y and returns a negative value if x < y, zero if x = y, or a positive value if x > y.

大致說的意思是,我不管你排序的演算法穩不穩定,反正你能給使用者自定義排序規則就行,不給你就愛咋折騰咋折騰~

這幫瀏覽器一聽,好啊,老大發話了,那就八仙過海各顯神通,各自都認為自己的實現是最牛逼的。

Chrome的sort

基於V8引擎,它的排序算進行了很多的優化,但是核心是小於等於10的陣列用插入排序(穩定),大於10的採用了quickSort(不穩定),原始碼

FireFox的sort

基於SpiderMonkey引擎,採用了歸併排序(穩定), 原始碼

Safari的sort

基於Nitro(JavaScriptCore )引擎,如果沒有自定義的排序規則傳入,採用桶排序(不一定穩定, 桶排序的穩定性取決於桶內排序的穩定性, 因此其穩定性不確定。),傳入自定義規則,採用歸併排序(穩定),原始碼

Microsoft Edge/IE9+

基於Chakra引擎,採用快排(不穩定)原始碼

好了,那個說sort可以不是偽排序的同學,你看見我這40米的大刀沒?

什麼,你還嘴硬,我喜歡你的性格,看下面:

github上的大神對 var letters = ['A','B','C','D','E',‘F’,‘G’,'H','I','J'];

進行了10000次亂序處理,發現結論: 元素大概率停留在自己的初始位置。

具體地址: HOUCe/shuffle-array

看見沒,矮要承認,捱打要立正。

洗牌演算法(Fisher-Yates)

想要實現真正意義上的亂序,我們來研究一下:只要滿足每個元素出現在各個位置的概率同等即可。

少年,聽過如來神掌嗎?

有個Fisher-Yates的洗牌演算法,滿足您的各種亂序需求,物美價廉,殺人越貨居家旅行的必備精品~(其實有三個版本,有興趣的自行搜尋)

演算法的大致描述

1.找到陣列的屁股(最後一個元素);

2.在腦袋和屁股中間隨機一個位置;

3.交換元素;

4.這時屁股是已經亂序後的元素,所以屁股前移;

5.如果屁股沒打到腦袋上就繼續1~4的步驟

function shuffle(arr) {
    let length = arr.length,
        r      = length,
        rand   = 0;

    while (r) {
        rand = Math.floor(Math.random() * r--);
        [arr[r], arr[rand]] = [arr[rand], arr[r]];
    }

    return arr;
}複製程式碼

參考文獻

github.com/HOUCe/shuff…

en.wikipedia.org/wiki/Fisher…

efe.baidu.com/blog/talk-a…

segmentfault.com/a/119000001…


相關文章