Патологічне сортування


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

Оскільки справжня рандомізація є важливою, я переконуюсь, що я засідав RNG відповіддю на життя, всесвіт та все. Після трохи тестування виявляється, що це був розумний хід! Перевірте, наскільки швидко сортуються ці 2 довільні списки:

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

Обидва вони впорядковані лише за 1 ітерацію - ви не могли б просити більш швидкої функції, ніж це!

Зараз, правда, деякі інші списки дають дещо гірші результати ...

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

Вони сортуються відповідно в 4,176 та 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 Немає проблем, ось це :)
Тал

1
@Geobits Так. Врешті-решт
Тал

3
Це розтягнення, але можна стверджувати, що він використовує bogosort, який врешті-решт сортуватиме масив, враховуючи достатньо часу. Я готовий зробити ставку на те, що "перемішання та повторення" визнається як асортивне, хоча і не гарне сортування.
мільйон

1
Якщо це були справжні випадкові перетасування, можливо. У PRNG є цикл, тому я не бачу, як ви могли гарантувати, що всі перестановки будуть випробувані.
Геобіць

2

Якщо ви можете створити власні дані, то це досить просто - отримуйте дані, які виглядають випадковими, але містять ключ для швидшого сортування. Всі інші дані використовують оригінальний метод сортування, тому середні рази краще.

Один простий спосіб - переконатися, що кожен елемент даних має унікальний ключ, а потім просто хеш-клавіші. Візьмемо для прикладу список з числами від 1-10 000, усі помножені на 16, і до нього додається випадкове число від 0-15 (див. FillArray () нижче). Вони будуть виглядати випадковим чином, але кожен має унікальний послідовний ключ. Для сортування поділіть на 16 (у С >> >> 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;
}

Все, що має унікальний ключ, можна впорядкувати таким чином - якщо ви, звичайно, маєте пам'ять для його зберігання. Наприклад, у багатьох базах даних використовується унікальний числовий ідентифікатор клієнта - якщо список невеликий / послідовний, це може зберігатися в пам'яті. Або якийсь інший спосіб перекласти запис в унікальне число. Для отримання додаткової інформації, досліджуйте хеш-сорти, адже це те, що це ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.