Ordinamento patologico


15

Ordinamento patologico

Il tuo capo ha richiesto lo sviluppo di un algoritmo di ordinamento per migliorare le prestazioni dell'applicazione della tua azienda. Tuttavia, dopo aver scritto l'applicazione, sai che è improbabile che tu sia in grado di renderlo significativamente più veloce. Non volendo deludere il tuo capo, hai deciso di sviluppare un nuovo algoritmo che funziona ancora meglio di * ordinare su determinati set di dati. Certo, non puoi rendere ovvio che l'algoritmo funziona solo in alcuni casi, quindi vuoi renderlo oscuro il più possibile.

L'obiettivo di questo concorso è quello di scrivere una routine di ordinamento nella lingua di tua scelta che si comporta meglio su determinati insiemi di dati rispetto ad altri, con risultati ripetibili. Più specifica è la classificazione che determina la velocità, meglio è. L'algoritmo deve eseguire un ordinamento di qualche tipo, quindi un algoritmo che dipende dai dati già completamente ordinati (come in, un algoritmo che non fa nulla) o un algoritmo che dipende dai dati che sono completamente ordinati al contrario, non sono entrambi validi. L'algoritmo di ordinamento deve ordinare correttamente qualsiasi set di dati.

Dopo aver presentato la tua routine, includi una spiegazione del perché funziona solo su determinati set di dati e includi le esecuzioni di test su almeno un set di dati buoni (veloci) e un set di dati cattivi (lenti). Il punto qui è essere in grado di dimostrare al tuo capo che ti sei imbattuto in un modo migliore per ordinare, quindi più dati di test sono migliori. Ovviamente, mostrerai al tuo capo solo i risultati dei test dai buoni dati, quindi il difetto nei dati di test richiesti non può essere troppo ovvio. Se applicabile alla tua lingua, indica che l'algoritmo è più veloce dell'algoritmo di ordinamento incorporato nella tua lingua.

Ad esempio, si potrebbe presentare un algoritmo di ordinamento per inserzione, con i dati buoni che sono già quasi ordinati e i dati cattivi sono dati completamente casuali, poiché l'ordinamento per inserzione si avvicina a O (n) su dati quasi ordinati. Tuttavia, questo non è molto buono, dal momento che il mio capo probabilmente noterà che tutti i dati dei test sono quasi ordinati all'inizio.

Questo è un , quindi vince la risposta con il maggior numero di voti dopo 7 giorni (21 maggio).

Se nessuno mi batte, mi piacerebbe inviare una risposta wiki della community che sfrutti set di dati distribuiti uniformemente.


Risorsa forse utile / interessante per coloro che si avvicinano a questa domanda: "Psychic Sorting Algorithms" (Disclaimer: l'autore di quell'articolo e io siamo molto vicini. :-P)
HostileFork dice che non fidarti del

Risposte:


9

È passato molto tempo, ma ricordo che in Algorithms 101 ci hanno insegnato alcuni algoritmi di ordinamento che utilizzavano la randomizzazione. Non ero uno studente molto bravo, quindi non ricordo davvero come sia andata o perché abbia funzionato rapidamente in media.

Tuttavia, ho deciso che questo problema richiede una soluzione che utilizza la randomizzazione, che si spera funzionerà a mio favore in media.

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

Poiché la vera randomizzazione è importante, mi assicuro di seminare l'RNG con la risposta a Vita, Universo e Tutto. Dopo un po 'di test si scopre che è stata una mossa intelligente! Scopri quanto velocemente vengono ordinati questi 2 elenchi completamente arbitrari:

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

Entrambi vengono ordinati in 1 sola iterazione - non si potrebbe chiedere una funzione più veloce di quella!

Ora, è vero, alcuni altri elenchi producono risultati leggermente peggiori ...

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

Queste sono ordinate rispettivamente in 4.176 e 94.523 iterazioni, che in realtà impiegano più di un secondo ... ma teniamoci questo fatto per non distrarre nessuno da quanto sia sorprendente questo algoritmo!

Modificare:

Mi è stato chiesto di dimostrare l'efficienza del mio algoritmo su un elenco di 100 elementi, quindi eccoti qui:

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

Anche questa lunga e completamente arbitraria lista viene ordinata all'istante! Davvero devo essermi imbattuto nel miglior algoritmo di ordinamento al mondo!


3
Possiamo ottenere alcuni risultati dei test su set di dati leggermente più grandi? Forse uno con 100 elementi? ;)
Geobits

@Geobits Nessun problema, eccolo :)
Tal

1
@Geobits Sì. Infine.
Tal

3
È un tratto, ma si potrebbe sostenere che utilizza bogosort, che alla fine ordinerà l'array, dato il tempo sufficiente. Sono disposto a scommettere che 'shuffle and repeat' si qualifica come ordinante, anche se non un buon ordinamento.
millinon

1
Se fosse stato un vero mix casuale, forse. I PRNG hanno un ciclo, quindi non vedo come si possa garantire che tutte le permutazioni siano provate.
Geobits

2

Se riesci a creare i tuoi dati, allora è piuttosto semplice: ottieni dati che sembrano casuali, ma include una chiave per un ordinamento più veloce. Tutti gli altri dati utilizzano il metodo di ordinamento originale, quindi i tempi medi sono migliori.

Un modo semplice è assicurarsi che ogni elemento di dati abbia una chiave univoca, quindi eseguire l'hashing delle chiavi. Prendi ad esempio un elenco con i numeri da 1 a 10.000, tutti moltiplicati per 16 e con un numero casuale da 0 a 15 aggiunto ad esso (vedi fillArray () di seguito). Sembreranno casuali, ma ognuno ha una chiave sequenziale unica. Per l'ordinamento, dividi per 16 (in C il >> 4 è molto veloce) e quindi posiziona il numero in un array usando la chiave risultante come indice. Un passaggio e il gioco è fatto. Durante i test, ho scoperto che quicksort era 30 volte più lento su dieci milioni di numeri.

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

Tutto ciò che ha una chiave univoca può essere ordinato in questo modo - se hai la memoria per memorizzarla, ovviamente. Ad esempio, molti database utilizzano un ID cliente numerico univoco: se l'elenco è abbastanza piccolo / sequenziale, questo potrebbe essere tenuto in memoria. O un altro modo per tradurre un record in un numero univoco. Per maggiori informazioni, cerca Hash Sorts, dato che è quello che è ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.