JS隨機洗牌算法之數(shù)組隨機排序
推薦閱讀:JavaScript學習筆記之數(shù)組的增、刪、改、查
洗牌算法是一個比較形象的術語,本質上讓一個數(shù)組內的元素隨機排列。舉例來說,我們有一個如下圖所示的數(shù)組,數(shù)組長度為 9,數(shù)組內元素的值順次分別是 1~9:
從上面這個數(shù)組入手,我們要做的就是打亂數(shù)組內元素的順序:
代碼實現(xiàn)
維基百科上的 Fisher–Yates shuffle 詞條對洗牌算法做了詳細介紹,下面演示的算法也是基于其中的理論編寫的:
Array.prototype.shuffle = function() { var input = this; for (var i = input.length-1; i >=0; i--) { var randomIndex = Math.floor(Math.random()*(i+1)); var itemAtIndex = input[randomIndex]; input[randomIndex] = input[i]; input[i] = itemAtIndex; } return input; } var tempArray = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] tempArray.shuffle(); // and the result is... alert(tempArray);
在上面的代碼中,我們創(chuàng)建了一個 shffle() 方法,該方法用于隨機排列數(shù)組內的元素。此外,我們將該方法掛載在了 Array 對象的原型下面,所以任何數(shù)組都可以直接調用該方法:
var tempArray = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] tempArray.shuffle();
工作原理
看完代碼之后,讓我們看看它對數(shù)組都做了寫什么。首先,該方法選中數(shù)組的最后一個元素:
接下來確定挑選隨機元素的范圍,從數(shù)組的第一個元素到上一步選中的元素都屬于這一范圍:
確定范圍后,從中隨機挑選一個數(shù),這里假設隨機選中的元素為 4:
然后交換最后一個元素和隨機選中的元素的值:
上面的交換完成后,相當于我們完成了對數(shù)組最后一個元素的隨機處理。接下來選中數(shù)組內倒數(shù)第二的元素:
之所以從后往前處理,是因為這樣便于確定隨機選擇的范圍。這次我們假定隨機到的元素為 2:
接著交換倒數(shù)第一個元素和 2 號元素的值,完成對倒數(shù)第二個元素隨機排列的處理。然后是選中倒數(shù)第三個元素,重復之前的操作:
剩下的就是一些重復性的工作,不多做介紹了。
分析代碼
在上一節(jié)給各位用圖例演示了洗牌流程,下面我們從代碼本身看看洗牌流程。先從 shuffle 函數(shù)說起吧:
Array.prototype.shuffle = function() { var input = this; for (var i = input.length-1; i >=0; i--) { var randomIndex = Math.floor(Math.random()*(i+1)); var itemAtIndex = input[randomIndex]; input[randomIndex] = input[i]; input[i] = itemAtIndex; } return input; }
shuffle 函數(shù)掛載在 Array 對象的原型之下,便于數(shù)組直接調用該函數(shù)。在 shuffle 函數(shù)內部,this 引用的就是調用該 shuffle 的數(shù)組:
var input = this;
在上面的代碼中,我用一個新的變量引用 this,也就是調用 shuffle 函數(shù)的數(shù)組。下一步,看一下 for 循環(huán)內都干了什么:
for (var i = input.length-1; i >=0; i--) { var randomIndex = Math.floor(Math.random()*(i+1)); var itemAtIndex = input[randomIndex]; input[randomIndex] = input[i]; input[i] = itemAtIndex; }
該循環(huán)用于遍歷所有數(shù)組內的所有元素,并進行隨機交換。注意,遍歷順序是從后往前進行的,也就是說從 input.length-1 位置的元素開始,知道遍歷到數(shù)組中的第一個元素。遍歷過程中的位置由變量 i 指定。
這里的變量 i 就是上面圖例中被選中的元素:
洗牌算法
接下來,使用了兩行代碼在指定范圍內挑選一個隨機元素:
var randomIndex = Math.floor(Math.random()*(i+1)); var itemAtIndex = input[randomIndex];
變量 randomIndex 存儲了一個隨機數(shù),該隨機數(shù)可以用作數(shù)組的索引,進而提取一個隨機元素。注意,該隨機數(shù)的最大值并不是數(shù)組的長度,而是變量 i 的值。
確定了隨機元素的索引之后,用新的變量保存該元素的值,然后交換選中元素和隨機元素的值:
var itemAtIndex = input[randomIndex]; input[randomIndex] = input[i]; input[i] = itemAtIndex;
在這三行代碼中,第一行使用新的變量保存了隨機元素的值;第二行將選中元素 input[i] 的值賦給隨機元素 input[randomIndex];第三行就隨機元素的值 itemAtIndex 賦給選中元素 input[i]。本質上是一個互換兩個元素的值的過程,并不難理解。
至此,循環(huán)內的邏輯就介紹完了,剩下的都是重復操作。
隨機性測試
上圖是使用 Highcharts 制作的隨機性測試圖表,以可視化的方式校驗本文中洗牌算法的隨機性。每次刷新頁面都會重新計算和生成該圖表。
生成上圖的數(shù)據(jù)是這樣計算而來的:首先創(chuàng)建一個數(shù)組(上圖使用的數(shù)組為 [0, 1, 2 ... 18, 19, 20]),然后使用本文中的洗牌算法重新排序,排序完成后記錄每一個元素的值……以此步驟執(zhí)行 100000 次,最后對同一索引位置上的數(shù)值進行求和。如此執(zhí)行 10000 次之后,索引之間的總值應該相差不大。
由計算可得:
以上內容是小編給大家介紹的JS隨機洗牌算法之給數(shù)組隨機排序的相關敘述,希望對大家有所幫助!
相關文章
JavaScript中如何使用cookie實現(xiàn)記住密碼功能及cookie相關函數(shù)介紹
cookie是網(wǎng)站設計者放置在客戶端(瀏覽器)的小文本文件,cookie不僅能夠實現(xiàn)保存密碼功能,還可以通過cookie保存最近瀏覽記錄增加用戶體驗。本文給大家介紹js使用cookie實現(xiàn)記住密碼功能及cookie相關函數(shù)講解,感興趣的朋友一起看看吧2016-11-11Javascript前端UI框架Kit使用指南之kitjs事件管理
本文詳細介紹了Kitjs的事件管理功能,包括普通的Dom事件、Kit如何解決問題、代碼解析、注銷事件等。需要的朋友可以參考下。2014-11-11javascript實現(xiàn)二分查找法實現(xiàn)代碼
javascript實現(xiàn)二分查找法實現(xiàn)代碼...2007-11-11一文詳解JavaScript?如何將?HTML?轉成?Markdown
這篇文章主要介紹了一文詳解JavaScript如何將HTML轉成Markdown,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08