Подтвердить что ты не робот

Сортируйте массив целых чисел в нечетные, тогда даже

У меня есть проблема, которую я нашел на форуме алгоритмов в другом месте.

У меня есть массив со случайными числами (например, [5, 2, 7, 9, 2, 3, 8, 4]), который должен быть возвращен мне отсортированным по четному, четному. Порядок шансов/эвенов не важен, поэтому в примере это, вероятно, будет [5, 7, 9, 3, 2, 2, 8, 4].

Моя первая мысль заключалась в том, чтобы использовать функцию .reduce(), чтобы просто вставить их в два разных массива, а затем объединить их вместе, но для этой задачи есть некоторые дополнительные сложности.

Добавленные правила задачи состоят в том, что сортировка должна поддерживать постоянное дополнительное пространство и изменять массив на месте. Он также должен использовать алгоритм, который последовательно масштабируется с размером массива.

Какой алгоритм?

Судя по Wikipedia list, существует ряд алгоритмов, которые масштабируются последовательно и используют постоянное пространство. Я также нашел этот веб-сайт, который имеет приятный вид пузыря для использования (также размещен ниже), который кажется стабильным и соответствует моим правилам (я думаю?).

Я не уверен, что это правильный алгоритм для использования или как вообще подходить к этой части задачи.

Bubble:

  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;
  }
4b9b3361

Ответ 1

Никакая сортировка сортировки не будет масштабироваться линейно. К счастью, вы можете сделать это с помощью двух индексов в массиве. Вот основная идея.

Учитывая массив, 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]

Первый раз через цикл он обнаруживает, что "2" в индексе 1 четный. Затем он ищет назад от конца и находит "3" в индексе 5. Он меняет их:

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

В следующий раз через цикл, startIndex будет равно 2, а endIndex будет 4. startIndex будет увеличиваться за "7" и "9", когда startIndex будет равно endIndex и вы выходите из цикла.

Для аналогичной проблемы и аналогичного алгоритма см. проблема голландского национального флага.

Ответ 2

Попробуйте использовать простую сортировку, она дает то, что вы ожидаете

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;

Ответ 3

Просто одним индексом, условно дающим простые свопы, в O (n) время в O (1) пространстве вы можете сделать следующее. Обратите внимание, что я использовал деструктурирование массива для обмена. Можно также использовать временную переменную.

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

Ответ 4

Вы можете отсортировать массив на месте в постоянном пространстве, используя аналогичную методологию для популярных алгоритмов сортировки.

Имейте переменную, чтобы пометить индексы отсортированных в данный момент частей массива, а затем выполнить работу между элементами, находящимися между ними или оставив их на месте (в случае их нечетности - на месте уже отсортировано), или доводя их до конца, если они ровные.

Этот алгоритм 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 odd, it 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 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 an extra sorted number at the
    // end, so decrease "end"
    var temp = data[end];
    data[end] = subject;
    data[position] = temp;
    end--;
  }
}

console.log(data);

Ответ 5

Множество реализаций уже опубликовано, поэтому я хотел бы указать, как эта проблема уже решена в основном в любой инфраструктуре.

При атаке на этот вопрос, поучительно смотреть на quicksort. Или не быстро сортировать, а подоперацию quicksort "partition", которая решает практически ту же проблему.

Подоперация "partition" выполняет следующую задачу: учитывая последовательность чисел и сводную точку, на месте переставляйте элементы последовательности таким образом, чтобы все числа, меньшие, чем точка поворота, находились в левой части последовательности, а все числа, большие, чем точка поворота, находятся в правой части последовательности. (Числа, равные поворотному концу, посередине, но если вы не пытаетесь реально сделать это неправильно, это произойдет автоматически.)

Это почти то, что мы пытаемся сделать здесь: In-place переставить элементы таким образом, чтобы они были разделены на две стороны на основе двоичного теста. Для быстрой сортировки это меньше; для этой проблемы это нечетно.

Итак, если вы рассматриваете проблему такого характера (локальный раздел на основе бинарного предиката), наиболее удобным способом атаки является копирование вашей операции с разделом кода. Единственное релевантное соображение состоит в том, что здесь нет точки опоры, поэтому имейте в виду, к чему стремилась оперативная сортировка, и не пропускайте этот индекс.

Ответ 6

Если вы соглашаетесь дублировать память, вы можете сделать это с помощью простых старых функций JavaScript, так как вы не хотите, чтобы подмассивы сами сортировались:

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

Ответ 7

Да, ваша первая идея вычислить четные и четные числа была в порядке:

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

Ответ 8

Начните один указатель с фронта, который останавливается при четных значениях, а другой - от последнего, который останавливается при нечетных значениях. Поменяйте два значения и продолжайте, пока оба указателя не пересекаются друг с другом.

Кроме того, этот алгоритм имеет сложность 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;
}

Ответ 9

Это предложение, которое ищет непрерывные пары четных и неравномерных чисел. Когда он найден, пара свопит.

Алгоритм поддерживает порядок групп нечетных и четных чисел.

В основном он использует счетчик индексов и цикл 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; }

Ответ 10

По мне, это самый простой способ - если вам нужно объяснение, прочитайте ответ @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 
}