web-dev-qa-db-ja.com

整数の配列を奇数にソートしてから偶数にソートします

他のアルゴリズムフォーラムで見つけた問題があります。

奇数と偶数でソートされて返される乱数(たとえば_[5, 2, 7, 9, 2, 3, 8, 4]_)の配列があります。オッズ/イーブンの順序は重要ではないため、この例ではおそらく_[5, 7, 9, 3, 2, 2, 8, 4]_になります。

最初に考えたのは、.reduce()関数を使用して、2つの異なる配列にプッシュしてから結合することでしたが、このタスクにはいくつかの複雑さが追加されました。

タスクに追加されたルールは、ソートで一定の余分なスペースを維持し、配列を適切に変更することです。また、配列のサイズに合わせてスケーリングするアルゴリズムを使用する必要があります。

どのアルゴリズムですか?

ウィキペディアのリスト から判断すると、一貫してスケーリングし、一定のスペースを使用するアルゴリズムがいくつかあります。また、 このウェブサイト を使用するニースのバブルソートがあり(これも下に掲載されています)、安定しているようで、ルールに従います(私は思う?)

これが適切なアルゴリズムであるかどうか、またはタスクのこの部分にアプローチする方法がまったくわかりません。

バブル:

_  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;
  }
_
20
germainelol

単純なソートを使用してみてください、それはあなたが期待するものを提供します

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;
10

条件付きで単純なスワップを生成する単一のインデックスによって、in O(n) time in O(1) space次のように実行できます。スワップに配列の構造化を使用しました。一時変数も使用することもできます。

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)));

編集:だから@Nina Scholzが示唆したように、同じアルゴリズムをオッズを数えることで同様の方法で実装することができますが、もっと簡単に見えるかもしれません。 (e & 1は、パリティをテストするためのe % 2と実質的に同じです。奇数は1(真)、偶数は0(偽)になります)

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)));
5
Redu

既に多数の実装が投稿されているため、基本的にあらゆるインフラストラクチャでこの問題がどのように既に解決されているかを指摘したいと思います。

この質問を攻撃するとき、クイックソートを見ることは有益です。または、クイックソートではなく、クイックソートの「パーティション」サブオペレーションで、本質的に同じ問題を解決しています。

「パーティション」サブオペレーションは、次のタスクを実行します。一連の数字とピボットを指定して、ピボットのすべての数字がシーケンスの左側にあり、すべての数字が次の数字よりも大きいように、シーケンスの要素をインプレース置換しますピボットはシーケンスの右側にあります。 (ピボットに等しい数は最終的には真ん中になりますが、実際に真剣に間違えようとしない限り、これは自動的に行われます。)

それはほとんど正確にここでやろうとしていることです:バイナリテストに基づいて要素を2つの側面に分離するように要素をインプレース置換します。クイックソートの場合、それは以下です。この問題の場合、それは奇妙です。

したがって、この性質の問題(バイナリ述語に基づくインプレースパーティション)を検討している場合、攻撃する最も便利な方法は、コードベースのパーティション操作をコピーして貼り付けることです。関連する唯一の考慮事項は、ここにピボットがないことです。したがって、クイックソートがどこに移動したかを覚えておいてください。そのインデックスをスキップしないでください。

4
Sneftel

一般的な並べ替えアルゴリズムと同様の方法論を使用して、一定のスペースで配列を並べ替えることができます。

配列の現在ソートされている部分のインデックスをマークする変数を用意し、その間のアイテムをその場で残すか(奇数の場合-既にソートされている場合)、または彼らが偶数なら終わり。

このアルゴリズムはO(n)で、必要なスペースは配列のサイズです。これらは両方とも、配列のサイズに応じて線形に拡大縮小します。

var data = [5, 2, 7, 9, 2, 3, 8, 4];

// end holds the position of the last unsorted number
var end = data.length - 1;
// start holds the position of the first unsorted number
var start = 0;
// position is the current index of the number which is of interest 
var position = start;

// while the two sorted halves have not met
while (start < end) {
  var subject = data[position];
  if (subject % 2 === 1) {
    // it's odd, it's already in the correct half of the array
    // so move to the next number, and increase start, marking this
    // number as sorted
    position++;
    start++;
  } else {
    // it's even, move it to the even sorted section. The means that
    // the number in "position" has not been looked at yet, so do not
    // increase "position", but there's an extra sorted number at the
    // end, so decrease "end"
    var temp = data[end];
    data[end] = subject;
    data[position] = temp;
    end--;
  }
}

console.log(data);
4
iblamefish

メモリーの複製を受け入れた場合、サブアレイをそれ自体でソートしたくないため、これを単純な古いJavaScript関数で実行できます。

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

はい、奇数と偶数を計算する最初のアイデアはうまくいきました。

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);
2
kevin ternet

これは、偶数と不均等の連続したペアを探す提案です。見つかった場合、ペアはスワップします。

アルゴリズム順序を保持奇数および偶数のグループ。

基本的には、インデックスカウンタと、バックトラッキングメカニズムを備えた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
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]
.as-console-wrapper { max-height: 100% !important; top: 0; }

これは基本的に同じですが、すでにアクセスしたアイテムの反復回数が少なくなります。

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);
.as-console-wrapper { max-height: 100% !important; top: 0; }
2
Nina Scholz

偶数の値で停止する前から1つのポインターを開始し、奇数の値で停止する最後から1つのポインターを開始します。 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;
}
2
Dinesh Verma

私によると、これは最も簡単な方法です-説明が必要な場合は、@ 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 
}
1
edc65

この場合の最も簡単で簡単な方法は、「ビット単位のオペランド」を使用して、並べ替え方法とともに各配列要素の最下位ビットにアクセスすることです。

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]));

以上です。完全に順序付けられてソートされたオッズの配列、...偶数を取得します。

0
user8201502