如何在 JavaScript 中实现蝴蝶洗牌算法?


在 JavaScript 中,蝴蝶洗牌数组是指一个数字数组,其排序方式为:越靠近数组中心,数字越小;越靠近数组两端,数字越大。最大的数字位于第一个索引位置。

蝴蝶洗牌数组的另一种变体是:越靠近数组中心,数字越大;越靠近数组两端,数字越小。在这种情况下,最小的数字位于第一个索引位置。

对于有数学背景的人来说,这与高斯分布有些相似。

示例

假设我们有以下数组:

const arr = [8,2,6,3,9,1,4,5,0,7];

如果我们对其应用蝴蝶洗牌算法,输出将为:

[9, 7, 5, 3, 1,0, 2, 4, 6, 8]

可以看到,最大和第二大的数字位于数组的两端,最小的数字位于数组的中心。

另一种可能性是:

[0, 2, 4, 6, 8, 9, 7, 5, 3, 1]

我们的任务是编写一个函数,该函数接收一个数字数组和一个字符串作为第二个参数,字符串可以取两个值中的任何一个:“asc” 或 “des”。

  • 如果字符串为“des”,则我们必须按升序到降序的顺序对数组进行洗牌。

  • 如果字符串为“asc”,则我们必须按降序到升序的顺序对数组进行洗牌。

方法

  • 如果字符串为“asc”,我们首先按升序对数组进行排序,否则按降序排序。因此,假设函数被调用时带了“asc”,那么数组现在将如下所示:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  • 然后我们将数组分成两个数组,使相邻元素分布在不同的数组中。我们将元素推入一个数组,同时将其移到另一个数组的开头,这样一来,一个数组就会被反转,而无需我们手动进行反转操作。

这样形成的两个数组将如下所示:

[ 0, 2, 4, 6, 8 ] [ 9, 7, 5, 3, 1 ]
  • 现在,最后一步是连接这两个数组,之后我们将得到所需的数组。将所有这些代码放在一起,看起来就像这样:

示例

const array = [8,2,6,3,9,1,4,5,0,7];
const butterflyShuffle = (array, order = 'asc') => {
   //creating a new copy of array so that we dont mutate the original
array
   const arr = array.slice();
   //sorting ascending or descending based on the argument
   arr.sort((a, b) => order === 'asc' ? a-b : b-a);
   const first = [], second = [];
   //this variable will later help in determining which array is to be
reversed
   //and which one is to be concatenated to which
   //if length is even, it means that last element will go in second array
   //otherwise it will go in first array
   const isEven = arr.length % 2 === 0;
   for (let i = 0; i < arr.length; i++){
      if(i % 2 === 0){
         isEven ? first.push(arr[i]) : first.unshift(arr[i]);
         continue;
      };
      isEven ? second.unshift(arr[i]) : second.push(arr[i]);
   };
   return isEven ? second.concat(first) : first.concat(second);
};
console.log(butterflyShuffle(array));
console.log(butterflyShuffle(array, 'des'));

输出

控制台中的输出将为:

[
   9, 7, 5, 3, 1,
   0, 2, 4, 6, 8
]
[
   0, 2, 4, 6, 8,
   9, 7, 5, 3, 1
]

更新于: 2020-08-25

296 次浏览

开启你的 职业生涯

通过完成课程获得认证

开始学习
广告