javascript
js调整数组某些元素到指定位置顺序_如何将一个 JavaScript 数组打乱顺序?
1)首先,毫無疑問: @顧軼靈 軼靈大佬給出的Fisher–Yates shuffle 洗牌算法是最完美亂序的算法/方法之一了,正解無疑。
2)同時,很多答案提到了:
[12,4,16,3].sort(function() {
return .5 - Math.random();
});
這樣使用 sort 的方法。某些場景下,這樣的方法可以使用。但是這不是真正意義上的完全亂序,一些需求中(比如抽獎)這樣的寫法會出大問題。
3) 也有答案提到了優(yōu)秀的 lodash 庫 _.shuffle 方法。這也是正解,事實上翻開 lodash 源碼相關部分,這個方法正是采用了 Fisher–Yates shuffle 洗牌算法。感興趣的同學可以進行參閱。
到此,這個回答應該已經有了相對完善的解釋。但是最為優(yōu)秀的碼農,還是可以繼續(xù)“追根問底”。正好現(xiàn)在有點時間,我來針對這幾點,稍微解釋并拓展一下。
1) 為什么借助 sort 方法不是真正意義上的完全亂序?
先證明不完全性。為此實現(xiàn)一個腳本,我對
var letters = ['A','B','C','D','E','F','G','H','I','J'];
letters 這樣一個數組使用 array.sort 方法進行了 10000 次亂序處理,并把亂序的每一次結果可視化輸出。每個元素(ABCD...)出現(xiàn)的位置次數進行記錄:
不管點擊按鈕幾次,你都會發(fā)現(xiàn)整體亂序之后的結果絕對不是“完全隨機”。
比如 A 元素大概率出現(xiàn)在數組的頭部,J 元素大概率出現(xiàn)在數組的尾部,所有元素大概率停留在自己初始位置。
究其原因,在Chrome v8引擎源碼中,可以清晰看到,v8 在處理 sort 方法時,使用了插入排序和快排兩種方案。當目標數組長度小于10時,使用插入排序;反之,使用快排。
其實不管用什么排序方法,大多數排序算法的時間復雜度介于 O(n) 到 O(n2) 之間,元素之間的比較次數通常情況下要遠小于 n(n-1)/2,也就意味著有一些元素之間根本就沒機會相比較(也就沒有了隨機交換的可能),這些 sort 隨機排序的算法自然也不能真正隨機。
通俗的說,其實我們使用 array.sort 進行亂序,理想的方案或者說純亂序的方案是:數組中每兩個元素都要進行比較,這個比較有 50% 的交換位置概率。如此一來,總共比較次數一定為 n(n-1)。
而在 sort 排序算法中,大多數情況都不會滿足這樣的條件。因而當然不是完全隨機的結果了。
2) Fisher–Yates shuffle 洗牌算法是什么,為什么滿足需求?
這里,我們簡單借助圖形來理解,非常簡單直觀。你接下來就會明白為什么這是理論上的完全亂序(圖片來源于網絡)。
首先我們有一個已經排好序的數組:
Step1:
第一步需要做的就是,從數組末尾開始,選取最后一個元素。
在數組一共 9 個位置中,隨機產生一個位置,該位置元素與最后一個元素進行交換。
Step2:
上一步中,我們已經把數組末尾元素進行隨機置換。
接下來,對數組倒數第二個元素動手。在除去已經排好的最后一個元素位置以外的8個位置中,隨機產生一個位置,該位置元素與倒數第二個元素進行交換。
Step3:
理解了前兩部,接下來就是依次進行,如此簡單。
最后,我們實現(xiàn)代碼:
Array.prototype.shuffle = function() {
var array = this;
var m = array.length,
t, i;
while (m) {
i = Math.floor(Math.random() * m--);
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
當然這種代碼不是純凈的,這就屬于另一層面的問題了。純函數與非純,開發(fā)者可以依照自己的開發(fā)模式和習慣,自行考慮。
以上,前三段進行了總結。后面大篇幅進行了解釋。讀者可以根據需要進行閱讀。很多內容都是拾人牙慧,探究精神對于程序員來說還是很必要的。
總結
以上是生活随笔為你收集整理的js调整数组某些元素到指定位置顺序_如何将一个 JavaScript 数组打乱顺序?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 系统通知并发问题_iOS 14 系统又出
- 下一篇: 韩文版ie8 启用java_只有在启用了