推荐答案
// www.javascriptcn.com code example
function shuffleArray(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
// 示例
let myArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let shuffledArray = shuffleArray(myArray);
console.log(shuffledArray); // 输出乱序后的数组本题详细解读
核心思想:Fisher-Yates (Knuth) Shuffle 算法
Fisher-Yates 洗牌算法是一种高效且公平的乱序数组算法。其核心思想是从数组的最后一个元素开始,向前遍历数组,对于每个元素,随机选择一个小于或等于当前索引的元素,然后交换这两个元素的位置。
算法步骤:
- 倒序遍历: 从数组的最后一个元素(索引
arr.length - 1)开始,向前遍历到第一个元素(索引0)。 - 生成随机索引: 对于当前遍历到的元素(索引为
i),生成一个0到i之间的随机整数j。 - 交换元素: 将索引为
i的元素和索引为j的元素进行交换。 - 循环结束: 当遍历到数组的第一个元素时,算法结束。
代码解析:
函数定义:
function shuffleArray(arr) { ... }定义一个名为
shuffleArray的函数,接收一个数组arr作为参数。循环遍历:
for (let i = arr.length - 1; i > 0; i--) { ... }使用
for循环,从数组的末尾开始向前遍历。注意,循环条件是i > 0,因为当i为0时,没有必要进行交换(j的范围是0到i)。生成随机索引:
const j = Math.floor(Math.random() * (i + 1));
Math.random()返回一个0(包括)到1(不包括)的随机浮点数。乘以(i + 1)之后,得到0到i+1(不包括)之间的随机浮点数。Math.floor()向下取整,得到一个0到i之间的随机整数。交换元素:
[arr[i], arr[j]] = [arr[j], arr[i]];
使用 ES6 的解构赋值语法,简洁地交换数组中索引为
i和j的两个元素。返回数组:
return arr;
返回洗牌后的数组。
为什么使用倒序遍历?
倒序遍历是 Fisher-Yates 算法的关键。这样做可以确保在每次迭代中,每个元素都有相同的概率被放到随机的位置,从而保证洗牌的公平性。
示例:
示例代码展示了如何使用 shuffleArray 函数,并打印输出洗牌后的数组。
复杂度分析:
- 时间复杂度: O(n),其中 n 是数组的长度。算法需要遍历数组一次。
- 空间复杂度: O(1),算法是原地操作,只需要常数级的额外空间。