将整数数组排序为奇数,然后是偶数

时间:2017-01-07 08:09:10

标签: javascript arrays algorithm sorting

我在其他地方的算法论坛上发现了一个问题。

我有一个带有随机数的数组(例如,[5, 2, 7, 9, 2, 3, 8, 4])应该返回给我,然后按奇数排序。赔率/赔率的顺序并不重要,因此在示例中它可能是[5, 7, 9, 3, 2, 2, 8, 4]

我的第一个想法是使用.reduce()函数将它们分成两个不同的数组,然后将它们连接在一起,但这项任务有一些复杂性。

添加的任务规则是排序应保持一个恒定的额外空间,并在适当的位置修改数组。它还应该使用一种与数组大小一致的算法。

哪种算法?

根据Wikipedia's list来判断,有许多算法可以一致地扩展并使用恒定的空间量。我还发现this website有一个很好的冒泡排序可供使用(也在下面发布),看起来很稳定并遵循我的规则(我认为?)

我不确定这是否是正确使用的算法,或者根本不知道如何处理这部分任务。

气泡:

  function comparator(a, b) {
    return a - b;
  }
  /**
   * Bubble sort algorithm.<br><br>
   * Complexity: O(N^2).
   *
   * @example
   * var sort = require('path-to-algorithms/src/' +
   * 'sorting/bubblesort').bubbleSort;
   * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ]
   *
   * @public
   * @module sorting/bubblesort
   * @param {Array} array Input array.
   * @param {Function} cmp Optional. A function that defines an
   * alternative sort order. The function should return a negative,
   * zero, or positive value, depending on the arguments.
   * @return {Array} Sorted array.
   */
  function bubbleSort(array, cmp) {
    cmp = cmp || comparator;
    var temp;
    for (var i = 0; i < array.length; i += 1) {
      for (var j = i; j > 0; j -= 1) {
        if (cmp(array[j], array[j - 1]) < 0) {
          temp = array[j];
          array[j] = array[j - 1];
          array[j - 1] = temp;
        }
      }
    }
    return array;
  }

11 个答案:

答案 0 :(得分:18)

没有比较排序会线性扩展。幸运的是,您可以使用数组中的两个索引来执行此操作。这是基本的想法。

给定一个已填充的数组a

startIndex = 0
endIndex = a.length - 1
while (startIndex < endIndex)
{
    // Skip over odd numbers at the front of the array
    while (startIndex < endIndex && (a[startIndex] % 2) != 0)
        ++startIndex;
    if (startIndex >= endIndex)
        break;
    // startIndex points to an even number
    // now look for the first odd number at the end of the array
    while (startIndex < endIndex && (a[endIndex] % 2) == 0)
        --endIndex;
    if (startIndex >= endIndex)
        break;
    // swap the two items, placing the even number
    // towards the end of the array, and the odd number
    // towards the front.
    temp = a[startIndex];
    a[startIndex] = a[endIndex];
    a[endIndex] = temp;
    // and adjust the indexes
    ++startIndex;
    --endIndex;
}

所以,给出你的示例数组:

[5, 2, 7, 9, 2, 3, 8, 4]

首次通过循环,它发现索引1处的'2'是偶数。然后它从末尾向后搜索并在索引5处找到'3'。它交换它们:

[5, 3, 7, 9, 2, 2, 8, 4]

下一次循环,startIndex将为2,endIndex将为4. startIndex增加超过'7'和'9',此时{{1}等于startIndex,你就会脱离循环。

对于类似问题和类似算法,请参阅Dutch national flag problem

答案 1 :(得分:10)

尝试使用简单排序,它可以提供您期望的结果

var data = [5, 2, 7, 9, 2, 3, 8, 4];
data.sort(function(a, b) {
  return b % 2 - a % 2
});
console.log(data);
// [5, 7, 9, 3, 2, 2, 8, 4]

// % is mod, 5 % 2 = 1; 2 % 2 = 0;

答案 2 :(得分:5)

只需通过一个有条件地产生简单交换的索引,在O(1)空间的O(n)时间内,您可以执行以下操作。请注意,我已使用数组解构来交换。人们也可以选择使用临时变量。

&#13;
&#13;
function sortByParity(a){
  var ec = 0; // Even count
  for (var i = 0; i < a.length; i++){
    a[i] & 1 ? [a[i],a[i-ec]] = [a[i-ec],a[i]] // If odd then swap accordingly
             : ec++;                           // If even increment even count
  }
  return a;
}

var arr = [5,2,7,9,2,3,8,1,6,4],
    brr = [0,2,4,6,8,1,3,5,7,9],
    crr = [1,2,3,4,5,6,7,8,9,0];
console.log(JSON.stringify(sortByParity(arr)));
console.log(JSON.stringify(sortByParity(brr)));
console.log(JSON.stringify(sortByParity(crr)));
&#13;
&#13;
&#13;

编辑:因为@Nina Scholz建议通过计算赔率可以以类似的方式实现相同的算法,但看起来可能更简单。 (e & 1实际上与e % 2相同,用于测试奇偶校验。赔率将导致1(真),而均衡将导致0(假))

&#13;
&#13;
function sortByParity(arr){
  var oc = 0;
  arr.forEach((e,i,a) => e & 1 && ([a[i], a[oc++]] = [a[oc], a[i]]));
  return arr;
}
              
var arr = [5,2,7,9,2,3,8,1,6,4],
    brr = [0,2,4,6,8,1,3,5,7,9],
    crr = [1,2,3,4,5,6,7,8,9,0];
console.log(JSON.stringify(sortByParity(arr)));
console.log(JSON.stringify(sortByParity(brr)));
console.log(JSON.stringify(sortByParity(crr)));
&#13;
&#13;
&#13;

答案 3 :(得分:4)

您可以使用与常用排序算法类似的方法,在恒定空间中对数组进行排序。

有一个变量来标记数组当前已排序部分的索引,然后处理它们之间的项目,或者将它们留在适当的位置(如果它们已经是奇怪的 - 就位已经排序) ,如果他们是平等的,或者将它们移到最后。

此算法为saveMessageToVariable,空间要求是数组的大小。这两者都与阵列的大小成线性关系。

&#13;
&#13;
O(n)
&#13;
&#13;
&#13;

答案 4 :(得分:4)

已经发布了大量实现,所以我想指出这个问题在基本上任何基础设施中是如何解决的。

在攻击这个问题时,看看快速排序是有益的。或者不是快速排序,而是快速排序&#34;分区&#34;子操作,这解决了基本相同的问题。

&#34;分区&#34;子操作完成以下任务:给定一系列数字和一个枢轴,就地置换序列的元素,使得小于枢轴的所有数字都在序列的左侧,并且所有大于枢轴的数字都在序列的右侧。 (数字等于枢轴在中间结束,但除非你尝试真正的真正难以弄错,否则这将自动发生。)

这几乎完全我们在这里尝试做的事情:就地置换元素,使得它们基于二元测试分成两面。对于小于的快速排序;对于这个问题,它很奇怪。

因此,如果您正在查看这种性质的问题(基于二进制谓词的就地分区),最方便的攻击方法是复制粘贴代码库的分区操作。唯一相关的考虑因素是这里没有任何支点,所以请记住quicksort将其移至的位置,并且不要跳过该索引。

答案 5 :(得分:3)

如果您接受复制内存,可以使用普通的旧JavaScript函数执行此操作,因为您不希望子数组自行排序:

var res = [];
for(var i = 0; i < input.length; ++i)
  If (input [i] % 2)
      res.unshift (input[i])
  else
      res.push(input [i])

答案 6 :(得分:2)

是的,你首先想到计算奇数偶数的想法很好:

var input = [5, 2, 7, 9, 2, 3, 8, 4];
var result = input.filter(x => x%2).sort().concat(input.filter(x => x%2 === 0).sort());
console.log(result);

答案 7 :(得分:2)

从前面开始一个指针,它停在偶数值,另一个从最后一个停在奇数值。交换这两个值并继续,直到两个指针相互交叉。

此外,该算法具有复杂度O(n)。

function SortThisArray(arr) {

  var startIndex = 0;
  var endIndex = arr.length - 1;

  while(startIndex < endIndex) {

    if(arr[startIndex] % 2 == 0 && arr[endIndex] % 2 == 1) {
      var temp = arr[startIndex];
      arr[startIndex] = arr[endIndex];
      arr[endIndex] = temp;
    }

    if(arr[startIndex] % 2 == 1) 
      startIndex++;      

    if(arr[endIndex] % 2 == 0)
      endIndex--;
  }

  return arr;
}

答案 8 :(得分:2)

这是一个寻找连续的偶数和不均匀数字的提议。找到后,那对交换。

算法保持奇数和偶数组的顺序

基本上,如果找到一对,它使用索引计数器和带有反向跟踪机制的while循环,那么如果索引大于零,则递减。

例如,这是数组的遍历:

        array                        comment
---------------------    --------------------------------
5 7 2 8 7 9 2 1 4 6 8    found even odd couple at index 3
      ^ ^                swap items, decrement index by 1
5 7 2 7 8 9 2 1 4 6 8    found even odd couple at index 2
    ^ ^
5 7 7 2 8 9 2 1 4 6 8    found even odd couple at index 4
        ^ ^
5 7 7 2 9 8 2 1 4 6 8    found even odd couple at index 3
      ^ ^
5 7 7 9 2 8 2 1 4 6 8    found even odd couple at index 6
            ^ ^
5 7 7 9 2 8 1 2 4 6 8    found even odd couple at index 5
          ^ ^
5 7 7 9 2 1 8 2 4 6 8    found even odd couple at index 4
        ^ ^
5 7 7 9 1 2 8 2 4 6 8    final result

&#13;
&#13;
var a = [5, 2, 7, 8, 7, 9, 2, 1, 4, 6, 8],
    i = 0,
    temp;

while (i < a.length - 1) {
    if (!(a[i] % 2) && a[i + 1] % 2) {
        temp = a[i];      
        a[i] = a[i + 1];
        a[i + 1] = temp;
        i && i--;
        continue;
    }
    i++;
}

console.log(a); // [5, 7, 7, 9, 1, 2, 8, 2, 4, 6, 8]
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

这基本相同,但对已访问过的项目的迭代次数较少。

&#13;
&#13;
var a = [0, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 1],
    i = 0,
    j,
    temp;

while (i < a.length - 1) {
    j = i;
    while (!(a[j] % 2) && a[j + 1] % 2) {
        temp = a[j];
        a[j] = a[j + 1];
        a[j + 1] = temp;
        if (!j) {
            break;
        }
        j--;
    }
    i++;
}

console.log(a);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

答案 9 :(得分:2)

据我所知,这是最简单的方法 - 如果您需要解释,请阅读@Dinesh Verma的答案

它是单次传递,仅使用3个变量作为额外存储

function sort(list)
{
  var bottom=0
  var top=list.length-1
  var swap
  while(bottom < top)
  {
    if (list[bottom] % 2 == 1) 
      ++bottom
    else if (list[top] % 2 == 0)
      --top
    else {
      swap = list[bottom]
      list[bottom] = list[top]
      list[top] = swap

    }
  }
  return list 
}

答案 10 :(得分:0)

在这种情况下,最简单和最简单的方法是使用“按位操作数”进行访问 每个数组元素的最低有效位以及排序方法:

function sortArray(array) {
let safe = [];
let mysort = Array.prototype.sort;
let mysplice = Array.prototype.splice;
 function zipit(arg){return arg[0];}
array.forEach(function(e){safe.push(e & 1);}); 
let odds = array.filter(function(e){
return (e & 1);}).sort(function(a,b){return a-b;});
let evens = array.filter(function(e){
return !(e & 1);}).sort(function(a,b){return b-a;});
let res = safe.map(function(ele,x){ return ( ele ) ? zipit(mysplice.call(odds,0,1)) : zipit(mysplice.call(evens,0,1));});
return res;
}

console.log(sortArray([2,3,2,1,5,6,7,8]));

就是这样。你得到一个完美的订单&amp;排序的赔率数组,......甚至。