Как отсортировать массив по минимальному количеству записей? - PullRequest
16 голосов
/ 02 сентября 2010

Мой друг задал вопрос в своем интервью:

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

Ответы [ 6 ]

29 голосов
/ 04 октября 2010

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

Алгоритм, который в два раза лучше сортировки выбора, это сортировка по циклу , которая не меняет местами.Цикл сортировки даст максимум n записей на сортировку.Количество записей абсолютно минимизировано.Он будет записывать число только один раз до конечного пункта назначения, и только тогда, если его там еще нет.

Он основан на идее, что все перестановки являются продуктами циклов , и вы можете простоциклически проходите каждый цикл и записывайте каждый элемент на свое место один раз.

import java.util.Random;
import java.util.Collections;
import java.util.Arrays;

public class CycleSort {
  public static final <T extends Comparable<T>> int cycleSort(final T[] array) {
    int writes = 0;

    // Loop through the array to find cycles to rotate.
    for (int cycleStart = 0; cycleStart < array.length - 1; cycleStart++) {
      T item = array[cycleStart];

      // Find where to put the item.
      int pos = cycleStart;
      for (int i = cycleStart + 1; i < array.length; i++)
        if (array[i].compareTo(item) < 0) pos++;

      // If the item is already there, this is not a cycle.
      if (pos == cycleStart) continue;

      // Otherwise, put the item there or right after any duplicates.
      while (item.equals(array[pos])) pos++;
      {
        final T temp = array[pos];
        array[pos] = item;
        item = temp;
      }
      writes++;

      // Rotate the rest of the cycle.
      while (pos != cycleStart) {
        // Find where to put the item.
        pos = cycleStart;
        for (int i = cycleStart + 1; i < array.length; i++)
          if (array[i].compareTo(item) < 0) pos++;

        // Put the item there or right after any duplicates.
        while (item.equals(array[pos])) pos++;
        {
          final T temp = array[pos];
          array[pos] = item;
          item = temp;
        }
        writes++;
      }
    } 
    return writes;
  }

  public static final void main(String[] args) {
    final Random rand = new Random();

    final Integer[] array = new Integer[8];
    for (int i = 0; i < array.length; i++) { array[i] = rand.nextInt(8); }

    for (int iteration = 0; iteration < 10; iteration++) {
      System.out.printf("array: %s ", Arrays.toString(array));
      final int writes = cycleSort(array);
      System.out.printf("sorted: %s writes: %d\n", Arrays.toString(array), writes);
      Collections.shuffle(Arrays.asList(array));
    }
  }
}

Несколько примеров запуска:

array: [3, 2, 6, 1, 3, 1, 4, 4] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 6
array: [1, 3, 4, 1, 3, 2, 4, 6] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 4
array: [3, 3, 1, 1, 4, 4, 2, 6] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 6
array: [1, 1, 3, 2, 4, 3, 6, 4] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 6
array: [3, 2, 3, 4, 6, 4, 1, 1] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 7
array: [6, 2, 4, 3, 1, 3, 4, 1] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 6
array: [6, 3, 2, 4, 3, 1, 4, 1] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 5
array: [4, 2, 6, 1, 1, 4, 3, 3] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 7
array: [4, 3, 3, 1, 2, 4, 6, 1] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 7
array: [1, 6, 4, 2, 4, 1, 3, 3] sorted: [1, 1, 2, 3, 3, 4, 4, 6] writes: 7
array: [5, 1, 2, 3, 4, 3, 7, 0] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 5
array: [5, 1, 7, 3, 2, 3, 4, 0] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 6
array: [4, 0, 3, 1, 5, 2, 7, 3] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 8
array: [4, 0, 7, 3, 5, 1, 3, 2] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 7
array: [3, 4, 2, 7, 5, 3, 1, 0] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 7
array: [0, 5, 3, 2, 3, 7, 1, 4] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 6
array: [1, 4, 3, 7, 2, 3, 5, 0] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 7
array: [1, 5, 0, 7, 3, 3, 4, 2] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 7
array: [0, 5, 7, 3, 3, 4, 2, 1] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 4
array: [7, 3, 1, 0, 3, 5, 4, 2] sorted: [0, 1, 2, 3, 3, 4, 5, 7] writes: 7
14 голосов
/ 02 сентября 2010

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

Из википедии:

Другое ключевое отличие состоит в том, что сортировка выбора всегда выполняет Θ (n) перестановок, а сортировка вставки выполняет Θ (n 2 ) перестановок в среднем и худшем случаях.Поскольку подкачки требуют записи в массив, сортировка выбора предпочтительнее, если запись в память значительно дороже, чем чтение.Это обычно тот случай, если предметы огромные, а ключи маленькие. Другим примером, где время записи имеет решающее значение, является массив, хранящийся в EEPROM или Flash.Не существует другого алгоритма с меньшим перемещением данных.

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

Если вам интересно , это фантастический сайт визуализации сортировки , который позволяет вам наблюдать, как конкретные алгоритмы сортировки выполняют свою работу, а также "гонять" разные алгоритмы сортировки друг против друга.

3 голосов
/ 02 сентября 2010

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

Алгоритм должен выглядеть так:

i = 0

do
   search for the minimum in range [i..n)
   swap a[i] with a[minPos]
   i = i + 1
repeat until i = n.

Поиск минимума может стоить вам почти ничего, своп стоит 3 записи, i ++ - 1 ..

Это называется выбор сортировки , как указано пеплом. (Извините, я не знал, что это сортировка по выбору :()

1 голос
/ 02 сентября 2010

Один вариант для больших массивов следующий (при условии n элементов):

  1. Инициализировать массив из n элементов с номерами 0..n-1
  2. Сортировка массива с использованием любого алгоритма сортировки. В качестве функции сравнения сравните элементы входного набора с соответствующими номерами (например, для сравнения 2 и 4 сравните 2-й и 4-й элементы входного набора). Это превращает массив из шага 1 в перестановку, которая представляет отсортированный порядок входного набора.
  3. Перебирайте элементы в перестановке, записывая блоки в порядке, указанном в массиве. Это требует ровно n записей, минимум.

Чтобы выполнить сортировку на месте, на шаге 3 вместо этого вы должны идентифицировать циклы в перестановке и «повернуть» их по мере необходимости, чтобы получить отсортированный порядок.

0 голосов
/ 02 сентября 2010

Упорядочение, которое я имел в виду в O (n), похоже на сортировку выбора (предыдущий пост), полезную, когда у вас небольшой диапазон клавиш (или вы упорядочиваете числа между 2 диапазонами)

Если у вас есть массив чисел, где числа будут в диапазоне от -10 до 100, то вы можете создать массив из 110 и быть уверенным, что все числа будут вписываться туда, если вы рассматриваете повторяющиеся числа, идея одинакова, но у вас будут списки вместо чисел в отсортированном массиве

псевдо-идея такова

N: max value of your array
tosort //array to be sorted
sorted = int[N]

for i = 0 to length(tosort)
do
   sorted[tosort[i]]++;
end

finalarray = int[length(tosort)]

k = 0
for i = 0 to N
do
  if ( sorted[i] > 0 )
    finalarray[k] = i
    k++;
  endif
end

finalarray будет иметь окончательный отсортированный массив, и вы будете иметь o (N) операций записи, где N - диапазон массива. Еще раз, это полезно при использовании ключей внутри определенного диапазона, но, возможно, это ваш случай.

С уважением и удачи!

0 голосов
/ 02 сентября 2010

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

Если числа не находятся в диапазоне, лучший способ сделать это - использовать QuickSort или HeapSort, которые сортируют int O (Log2N) в обоих случаях, но некоторые предпочитают QuickSort, например, я.Вы можете найти реализацию QuickSort на любом языке практически в любом месте, просто Google, и вы найдете его в считанные секунды.

Адаптация HeapSort доступна при организации внешних данных, то есть данных, которые не в памяти, но на жестком диске, наиболее часто встречается при работе с огромными массивами.

Надеюсь, что смогу помочь С наилучшими пожеланиями и удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...