JS: 數組亂序


數組亂序


顧名思義,數組亂序就是把數組存儲的值的順序都打亂。

Fisher–Yates shuffle


著名的洗牌算法,原理就是遍歷數組元素,將當前元素與隨機抽取的一個剩余元素進行交換。

下列表格遍歷元素是從后往前:

隨機數范圍 隨機數 原始數據 結果
1 2 3 4 5 6
[ 0 , 5 ] 1 1 6 3 4 5 2
[ 0 , 4 ] 3 1 6 3 5 4 2
[ 0 , 3 ] 1 1 5 3 6 4 2
[ 0 , 2 ] 2 1 5 3 6 4 2
[ 0 , 1 ] 1 1 5 3 6 4 2
[ 0 , 0 ] 0 1 5 3 6 4 2

代碼如下:

function shuffle(arr) {
    for (let i=arr.length-1; i>=0; i--) {
        let rIndex = Math.floor(Math.random()*(i+1));
        // 打印交換值
        // console.log(i, rIndex);
        let temp = arr[rIndex];
        arr[rIndex] = arr[i];
        arr[i] = temp;
    }
    return arr;
}

shuffle([1,2,3,4,5,6]); // [1, 5, 3, 6, 4, 2]

現在測試一下是否真的實現了亂序:

// 使用 res 存儲結果
let res = {};
let times = 100000;
for (let i=0; i<times; i++) {
    // 使用 [1, 2, 3] 進行簡單測試
    let key = JSON.stringify(shuffle([1, 2, 3]));
    res[key] ? res[key]++ : res[key] = 1;
}
for (let key in res) {
    res[key] = Number.parseFloat(res[key]/times *100 ).toFixed(3) + '%';
}
// 從結果可以看出是實現了真正的亂序的
res; 
/*
[1,2,3]: "16.514%"
[1,3,2]: "16.764%"
[2,1,3]: "16.606%"
[2,3,1]: "16.587%"
[3,1,2]: "16.712%"
[3,2,1]: "16.817%"
*/

固定一個值


在亂序的同時,固定一個下標的值,使其位置不變,方法有很多,這里只給出一種:

function shuffle(arr, index) {
    let res = [];
    // 取出固定值
    let fix = arr.splice(index, 1)[0];
    for (let i=arr.length-1; i>=0; i--) {
        let rIndex = Math.floor(Math.random()*(i+1));
        res.push(arr[rIndex]);
        arr.splice(rIndex, 1);
    }
    // 將固定值放入指定位置
    res.splice(index, 0, fix);
    return res;
}
// 多次運行,可以看出數組下標為 1 的值始終是固定的
shuffle([1,2,3,4,5,6], 1);
// [5, 2, 6, 3, 1, 4]
// [5, 2, 6, 3, 4, 1]
// [3, 2, 4, 6, 1, 5]

這里同樣測試一下是否實現了真正的亂序:

let res = {};
let times = 100000;
for (let i=0; i<times; i++) {
    // 使用 [1, 2, 3] 進行簡單測試,固定數組下標 1 的值
    let key = JSON.stringify(shuffle([1, 2, 3], 1));
    res[key] ? res[key]++ : res[key] = 1;
}
for (let key in res) {
    res[key] = Number.parseFloat(res[key]/times *100 ).toFixed(3) + '%';
}
// 固定的同時,依然是亂序的
res;
/*
[1,2,3]: "49.976%"
[3,2,1]: "50.024%"
*/

注意


需要注意的是,因為數組是引用類型,所以上面的方法都會改變原數組,要想不改變原數組只需稍稍改動一下代碼即可,這個很簡單,就不寫了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM