Патологическая сортировка


15

Патологическая сортировка

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

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

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

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

Это , поэтому ответ с наибольшим количеством голосов через 7 дней (21 мая) выигрывает.

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


Возможно, полезный / интересный ресурс для тех, кто подходит к этому вопросу: «Алгоритмы психической сортировки» (Отказ от ответственности: автор этой статьи и я очень близки. :-P)
HostileFork говорит, что не доверяйте SE

Ответы:


9

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

Тем не менее, я решил, что эта проблема требует решения, которое использует рандомизацию, которая, надеюсь, в среднем будет работать в мою пользу.

import random

def arrayIsSorted (arr) :
    for i in range(len(arr)-1) :
        if arr[i]>arr[i+1] : return False
    return True

def rSort (arr) :
    random.seed (42)
    counter = 0
    while not arrayIsSorted(arr) :
        random.shuffle (arr)
        counter+=1
    print ("Sorted in %d iterations." % counter)
    return arr

Поскольку истинная рандомизация важна, я проверяю ГСЧ ответом на Жизнь, Вселенную и Всё. После небольшого тестирования выясняется, что это был разумный ход! Посмотрите, как быстро сортируются эти 2 совершенно произвольных списка:

rSort ([6,1,4,2,3,7,5])
rSort ([8,9,6,1,4,7,2,3,5])

Оба из них сортируются только за одну итерацию - вы не могли бы попросить более быструю функцию, чем это!

Теперь, по общему признанию, некоторые другие списки дают немного худшие результаты ...

rSort ([5,1,4,2,3,7,6])
rSort ([8,9,6,1,4,7,2,5,3])

Они сортируются в 4176 и 94 523 итерации соответственно, что на самом деле занимает больше секунды ... но давайте просто оставим этот факт при себе, чтобы никого не отвлекать от того, насколько удивителен этот алгоритм!

Редактировать:

Меня попросили доказать эффективность моего алгоритма в списке из 100 элементов, так что вот вам:

rSort ([70, 6, 52, 97, 85, 61, 62, 48, 30, 3, 11, 88, 39, 91, 98, 8, 54, 92, 44, 65, 69, 21, 58, 41, 60, 76, 27, 82, 93, 81, 20, 94, 22, 29, 49, 95, 40, 19, 55, 42, 43, 1, 0, 67, 35, 15, 51, 31, 16, 25, 5, 53, 37, 74, 86, 12, 13, 72, 56, 32, 47, 46, 59, 33, 80, 4, 45, 63, 57, 89, 7, 77, 14, 10, 34, 87, 18, 79, 9, 66, 24, 99, 64, 26, 78, 38, 90, 28, 83, 75, 68, 2, 17, 73, 96, 71, 23, 84, 36, 50])

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


3
Можем ли мы получить результаты тестов с немного большими наборами данных? Может быть, один из 100 элементов? ;)
Geobits

@Geobits Нет проблем, вот оно :)
Таль

1
@ Geobits Да, это так. В конце концов.
Тал

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

1
Может быть, если бы это были настоящие случайные тасовки. У PRNG есть цикл, поэтому я не вижу, как можно гарантировать, что все перестановки будут опробованы.
Geobits

2

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

Один простой способ - убедиться, что каждый элемент данных имеет уникальный ключ, а затем просто хешировать ключи. Возьмем, к примеру, список с числами от 1 до 10 000, все умноженные на 16, и со случайным числом от 0 до 15, добавленным к нему (см. FillArray () ниже). Они будут выглядеть случайными, но у каждого есть уникальный последовательный ключ. Для сортировки разделите на 16 (в C >> 4 очень быстро), а затем просто поместите число в массив, используя полученный ключ в качестве индекса. Один проход и все готово. При тестировании я обнаружил, что быстрая сортировка была в 30 раз медленнее на десятимиллионных числах.

void fillArray(int *a,int len)
{
  for (int i=0;i<len;++i)
    a[i]=(i<<4)|(rand()&0xF);
  // shuffle later
}
void sortArray(int *a,int len)
{
  int key=0;
  int *r=new int[len];
  for (int i=0;i<len;++i)
  {
    key=a[i]>>4;
    r[key]=a[i];
  }
  memcpy(a,r,len*sizeof(int));
  delete[] r;
}
void shuffleArray(int *a,int len)
{
  int swap=0, k=0;
  for (int i=0;i<len;++i)
  {
    k=rand()%len;
    swap=a[k];
    a[k]=a[i];
    a[i]=swap;
  }
}
int qCompare(const void*a,const void*b)
{
  int result=*((int*)a)-*((int*)b);
  return result;
}
void main()
{
  int aLen=10000;
  int *a=new int[aLen];
  srand (time(NULL));
  fillArray(a,aLen);
  // time them
  long t0=0, d0=0, d1=0;
  // qsort
  shuffleArray(a,aLen);
  t0=::GetTickCount();
  qsort(a,aLen,sizeof(int),&qCompare);
  d0=::GetTickCount()-t0;
  // oursort
  shuffleArray(a,aLen);
  t0=::GetTickCount();
  sortArray(a,aLen);
  d1=::GetTickCount()-t0;
  delete[] a;
}

Все, что имеет уникальный ключ, может быть отсортировано таким образом - если, конечно, у вас есть память для его хранения. Например, многие базы данных используют уникальный числовой идентификатор клиента - если список небольшой / достаточно последовательный, его можно хранить в памяти. Или каким-то другим способом перевести запись в уникальный номер. Для получения дополнительной информации, исследования Hash Sorts, так как это то, что это ...

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.