通過js隨機(jī)函數(shù)Math.random實(shí)現(xiàn)亂序
亂序的意思想必沒有不知道:就是將數(shù)組打亂。聽到亂序一般都會(huì)想到j(luò)s的隨機(jī)函數(shù)Math.random();
var values = [1, 2, 3, 4, 5];
values.sort(function() {
return Math.random() - 0.5;
});
console.log(values)
利用數(shù)組的sort方法,判斷隨機(jī)出來的0~1值與0.5的大小,實(shí)現(xiàn)排序。看似一個(gè)很不錯(cuò)的方案,代碼邏輯也沒毛病,一般情況下也確實(shí)能夠做到亂序。但是,這是一個(gè)偽排序,是的還有但是(我也是今天才知道的,不求甚解的毛病啊~),為什么呢?先看看這個(gè)亂序的結(jié)果吧:
var times = [0, 0, 0, 0, 0];
for (var i = 0; i < 100000; i++) {
let arr = [1, 2, 3, 4, 5];
arr.sort(() => Math.random() - 0.5);
times[arr[4] - 1]++;
};
console.log(times)
測(cè)試的原理是:將[1, 2, 3, 4, 5]亂序10萬次,計(jì)算亂序后數(shù)組的最后一個(gè)元素是1,2,3,4,5的次數(shù)分別是多少。
運(yùn)行幾次得到的結(jié)果為:



由這幾次運(yùn)行得到的結(jié)果可以看出:2出現(xiàn)的最后的次數(shù)明顯少于其他數(shù)字,不是隨機(jī)嗎?按理說概率應(yīng)該是相差不多才對(duì)?。?br />
其實(shí)問題是在sort方法,各個(gè)瀏覽器對(duì)sort的實(shí)現(xiàn)方式不一樣。
Chrome的sort
基于V8引擎,它的排序算進(jìn)行了很多的優(yōu)化,但是核心是小于等于10的數(shù)組用插入排序(穩(wěn)定),大于10的采用了quickSort(不穩(wěn)定)
FireFox的sort
基于SpiderMonkey引擎,采用了歸并排序(穩(wěn)定)
Safari的sort
基于Nitro(JavaScriptCore )引擎,如果沒有自定義的排序規(guī)則傳入,采用桶排序(不一定穩(wěn)定, 桶排序的穩(wěn)定性取決于桶內(nèi)排序的穩(wěn)定性, 因此其穩(wěn)定性不確定。),傳入自定義規(guī)則,采用歸并排序(穩(wěn)定)
Microsoft Edge/IE9+
基于Chakra引擎,采用快排(不穩(wěn)定)
以下用chrome測(cè)試亂序各種結(jié)果的概率:
var times = 100000;
var res = {};
for(var i = 0; i < times; i++){
var arr = [1, 2, 3];
arr.sort(() => Match.random() - 0.5);
var key = JSON.stringify(arr);
res[key] ? res[key]++ : res[key] = 1;
}
// 為了方便展示,轉(zhuǎn)換成百分比
for (var key in res) {
res[key] = res[key] / times * 100 + '%';
}
console.log(res);
結(jié)果如下

幾種結(jié)果出現(xiàn)的概率相差很大...所以說不是一個(gè)真正的亂序。
Fisher-Yates算法【也叫“洗牌算法”】:為什么叫 Fisher–Yates 呢? 因?yàn)檫@個(gè)算法是由 Ronald Fisher 和 Frank Yates 首次提出的。代碼如下:
function shuffle(a) {
var j, x, i;
for (i = a.length; i; i--) {
j = Math.floor(Math.random() * i);
x = a[i-1];
a[i - 1] = a[j];
a[j] = x;
}
return a;
}
其原理就是:遍歷數(shù)組元素,然后將當(dāng)前元素與以后隨機(jī)位置的元素進(jìn)行交換,這樣亂序更加徹底。
如果用ES6的寫法還能精簡(jiǎn)成:
function shuffle(a) {
for(let i = a.length; i; i--) {
let j = Math.floor(Math.random() * i);
[a[i - 1], a[j]] = [a[j], a[i - 1]];
}
return a;
}
再用上面的demo測(cè)試一下:
var times = 100000;
var res = {};
for (var i = 0; i < times; i++) {
var arr = shuffle([1, 2, 3]);
var key = JSON.stringify(arr);
res[key] ? res[key]++ : res[key] = 1;
}
// 為了方便展示,轉(zhuǎn)換成百分比
for (var key in res) {
res[key] = res[key] / times * 100 + '%'
}
console.log(res)
得到結(jié)果如下:

各種結(jié)果的概率都基本相同了,所以真正實(shí)現(xiàn)了亂序的效果!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- JavaScript DOM操作表格及樣式
- JavaScript與DOM組合動(dòng)態(tài)創(chuàng)建表格實(shí)例
- JavaScript DOM 學(xué)習(xí)第三章 內(nèi)容表格
- JavaScript 學(xué)習(xí)筆記(十三)Dom創(chuàng)建表格
- 詳解用js代碼觸發(fā)dom事件的實(shí)現(xiàn)方案
- JavaScript監(jiān)聽一個(gè)DOM元素大小變化
- Node.js Domain 模塊實(shí)例詳解
- JavaScript 實(shí)現(xiàn)HTML DOM增刪改查操作的常見方法詳解
- JS如何操作DOM基于表格動(dòng)態(tài)展示數(shù)據(jù)
相關(guān)文章
node.js使用nodemailer發(fā)送郵件實(shí)例
這篇文章主要介紹了node.js使用nodemailer發(fā)送郵件的方法,例子中使用的是QQ郵箱,你也可以修改成其它的郵箱如163、gmail等,需要的朋友可以參考下2014-03-03
JavaScript中16進(jìn)制顏色與rgb顏色互相轉(zhuǎn)換的示例代碼
這篇文章主要介紹了JavaScript中16進(jìn)制顏色與rgb顏色互相轉(zhuǎn)換的示例代碼,通過示例代碼介紹了JS 顏色16進(jìn)制、rgba相互轉(zhuǎn)換問題,感興趣的朋友一起看看吧2024-01-01
js實(shí)現(xiàn)點(diǎn)擊切換和自動(dòng)播放的輪播圖
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)點(diǎn)擊切換和自動(dòng)播放的輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07
點(diǎn)擊按鈕或鏈接不跳轉(zhuǎn)只刷新頁面的腳本整理
點(diǎn)擊按鈕或鏈接時(shí)不跳轉(zhuǎn)只刷新頁面,在某些情況下還是比較實(shí)用的,下面整理些不錯(cuò)的示例,感興趣的朋友可以參考下2013-10-10
原生JavaScript實(shí)現(xiàn)瀑布流布局
這篇文章主要介紹了原生JavaScript實(shí)現(xiàn)瀑布流布局的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-12-12

