JS - - - - - 数组乱序排序「进阶版」

1. 使用.sort()进行乱序排序

1.1 简单示例

function sortShuffle(arr) {
	return arr.sort(()=> Math.random() - 0.5);
}

function start() {
	for(let i = 0; i < 10; i++){
		let arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
		sortShuffle(arr);
		console.log('arr', arr)
	}
}


start()

在这里插入图片描述

打印的结果看似真的已经随机了,但是事实真的如此吗?

由于基数小,得到的数据不一定准确。接下来增加次数,以验证随机性的真实性。

1.2 加大基数

代码如下:

function sortShuffle(arr) {
	return arr.sort(()=> Math.random() - 0.5);
}

function start() {
	// 循环10w次
	let num = 100000;

	// 统计元素在每个位置出现的次数
	let elementPositionCounts = {
		a: Array.from({length:10}).fill(0),
		b: Array.from({length:10}).fill(0),
		c: Array.from({length:10}).fill(0),
		d: Array.from({length:10}).fill(0),
		e: Array.from({length:10}).fill(0),
		f: Array.from({length:10}).fill(0),
		g: Array.from({length:10}).fill(0),
		h: Array.from({length:10}).fill(0),
		i: Array.from({length:10}).fill(0),
		j: Array.from({length:10}).fill(0)
	}
	
	for(let i = 0; i < num;  i++){
		let arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
		sortShuffle(arr);
        elementPositionCounts.a[arr.indexOf('a')]++;
        elementPositionCounts.b[arr.indexOf('b')]++;
        elementPositionCounts.c[arr.indexOf('c')]++;
        elementPositionCounts.d[arr.indexOf('d')]++;
        elementPositionCounts.e[arr.indexOf('e')]++;
        elementPositionCounts.f[arr.indexOf('f')]++;
        elementPositionCounts.g[arr.indexOf('g')]++;
        elementPositionCounts.h[arr.indexOf('h')]++;
        elementPositionCounts.i[arr.indexOf('i')]++;
        elementPositionCounts.j[arr.indexOf('j')]++;
	}
	// 以表格形式,展示结果
	console.table(elementPositionCounts);
}

start()

在这里插入图片描述

从表格中可以明显看出,各元素在不同位置的出现概率存在显著差异

各列数据统计了不同元素在相同位置的出现频率
以第一列为例:
最高频元素"a"出现约19.5k
而最低频元素"i"仅出现约6k次。

2. 使用「洗牌算法 Fisher-Yates 」进行乱序排序

每次从未处理的数组中随机取一个元素,然后把该元素放到数组的尾部,即数组的尾部放的就是已经处理过的元素。
这是一种原地打乱的算法,每个元素随机概率也相等,时间复杂度从 Fisher 算法的 O(n2)提升到了 O(n)

// Fisher-Yates 洗牌算法
function shuffle(arr) {
  const array = [...arr]; // 创建副本,避免修改原数组
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1)); // 生成 [0, i] 的随机数
    [array[i], array[j]] = [array[j], array[i]]; // 交换元素 (解构赋值的方式交换位置)
  }
  return array;
}

function start() {
  const num = 100000; // 循环次数
  const elements = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];

  // 使用reduce初始化统计对象
  const elementPositionCounts = elements.reduce((acc, el) => {
    acc[el] = Array(elements.length).fill(0);
    return acc;
  }, {});

  // 进行洗牌并统计位置
  for (let i = 0; i < num; i++) {
    const shuffled = shuffle(elements);
    shuffled.forEach((el, pos) => {
      elementPositionCounts[el][pos]++;
    });
  }

  // 输出结果
  console.table(elementPositionCounts);
}

start();

结果如下:
在这里插入图片描述

从表格中我们可以看出,每个元素在每个位置出现的次数已经相差不大

每一列中各元素出现的次数基本已经很平均了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值