Clasificación patológica

15

Clasificación patológica

Su jefe le ha exigido que desarrolle un algoritmo de clasificación para mejorar el rendimiento de la aplicación de su empresa. Sin embargo, después de escribir la aplicación, sabe que es poco probable que pueda hacerla significativamente más rápida. No queriendo decepcionar a su jefe, ha decidido desarrollar un nuevo algoritmo que funciona incluso mejor que * ordenar en ciertos conjuntos de datos. Por supuesto, no puede hacer obvio que el algoritmo solo funciona en algunos casos, por lo que desea que sea lo más oscuro posible.

El objetivo de este concurso es escribir una rutina de clasificación en el idioma que elija que funcione mejor en ciertos conjuntos de datos que otros, con resultados repetibles. Cuanto más específica sea la clasificación que determina la velocidad, mejor. El algoritmo debe hacer algún tipo de clasificación, por lo que un algoritmo que depende de los datos que ya están completamente ordenados (como en un algoritmo que no hace nada), o un algoritmo que depende de los datos que se ordenan completamente a la inversa, ambos no son válidos. El algoritmo de ordenación debe ordenar correctamente cualquier conjunto de datos.

Después de presentar su rutina, incluya una explicación de por qué solo funciona en ciertos conjuntos de datos e incluya ejecuciones de prueba en al menos un conjunto de datos buenos (rápidos) y un conjunto de datos malos (lentos). El punto aquí es poder demostrarle a su jefe que ha encontrado una mejor manera de clasificar, por lo que más datos de prueba son mejores. Por supuesto, solo le mostrará a su jefe los resultados de la prueba de los datos correctos, por lo que la falla en los datos de prueba requeridos no puede ser demasiado obvia. Si corresponde a su idioma, demuestre que su algoritmo es más rápido que el algoritmo de clasificación incorporado en su idioma.

Por ejemplo, uno podría enviar un algoritmo de ordenamiento por inserción, siendo los datos buenos datos que ya están casi ordenados, y los datos malos son datos completamente aleatorios, ya que el ordenamiento por inserción se acerca a O (n) en datos casi ordenados. Sin embargo, esto no es muy bueno, ya que mi jefe probablemente notaría que todos los datos de prueba están casi ordenados para empezar.

Este es un , por lo que gana la respuesta con más votos después de 7 días (21 de mayo).

Si nadie me supera, me gustaría enviar una respuesta wiki comunitaria que aproveche los conjuntos de datos distribuidos uniformemente.

Millinon
fuente
Recurso posiblemente útil / interesante para quienes se acercan a esta pregunta: "Algoritmos de clasificación psíquica" (Descargo de responsabilidad: el autor de ese artículo y yo somos muy cercanos.
:-P

Respuestas:

9

Ha pasado bastante tiempo, pero recuerdo en Algoritmos 101 que nos enseñaron un algoritmo de clasificación que utilizaba la aleatorización. No era muy buen estudiante, así que realmente no recuerdo cómo fue o por qué funcionó rápidamente en promedio.

Sin embargo, he decidido que este problema requiere una solución que utilice la aleatorización, que con suerte funcionará a mi favor en promedio.

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

Dado que la aleatorización verdadera es importante, me aseguro de sembrar el RNG con la respuesta a Life, the Universe y Everything. ¡Después de un poco de prueba resulta que fue un movimiento inteligente! Vea qué tan rápido se ordenan estas 2 listas completamente arbitrarias:

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

Ambos se ordenan en solo 1 iteración: ¡no podrías pedir una función más rápida que esa!

Ahora, es cierto, algunas otras listas producen resultados ligeramente peores ...

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

Estos se ordenan en 4,176 y 94,523 iteraciones respectivamente, lo que en realidad lleva más de un segundo ... ¡pero guardemos ese hecho para no distraer a nadie de lo increíble que es este algoritmo!

Editar:

Me han pedido que pruebe la eficiencia de mi algoritmo en una lista de 100 elementos, así que aquí tienes:

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

¡Incluso esta lista larga y completamente arbitraria se ordena al instante! ¡Realmente debo haberme topado con el mejor algoritmo de clasificación del mundo!

Tal
fuente
3
¿Podemos obtener algunos resultados de pruebas en conjuntos de datos un poco más grandes? Tal vez uno con 100 elementos? ;)
Geobits
@Geobits No hay problema, aquí está :)
Tal
1
@Geobits Sí, lo hace. Finalmente.
Tal
3
Es una exageración, pero se podría argumentar que usa bogosort, que eventualmente clasificará la matriz, con el tiempo suficiente. Estoy dispuesto a apostar que "barajar y repetir" califica como una clasificación, aunque no es una buena clasificación.
Millinon
1
Si se trataba de barajar al azar, tal vez. Los PRNG tienen un ciclo, por lo que no puedo ver cómo podría garantizar que se prueben todas las permutaciones.
Geobits
2

Si puede crear sus propios datos, entonces es bastante sencillo: obtenga datos que parezcan aleatorios, pero que incluyen una clave para una clasificación más rápida. Todos los demás datos utilizan el método de clasificación original, por lo que los tiempos promedio son mejores.

Una manera fácil es asegurarse de que cada elemento de datos tenga una clave única, y luego simplemente hash las claves. Tomemos, por ejemplo, una lista con los números del 1 al 10,000, todos multiplicados por 16, y con un número aleatorio del 0 al 15 (ver fillArray () a continuación). Se verán al azar, pero cada uno tiene una clave secuencial única. Para ordenar, divida por 16 (en C el >> 4 es muy rápido) y luego coloque el número en una matriz usando la clave resultante como índice. Un pase y listo. En las pruebas, descubrí que la clasificación rápida era 30 veces más lenta en diez millones de números.

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

Cualquier cosa que tenga una clave única se puede ordenar de esta manera, si tiene memoria para almacenarla, por supuesto. Por ejemplo, muchas bases de datos usan una identificación de cliente numérica única; si la lista es lo suficientemente pequeña / secuencial, esto podría guardarse en la memoria. O alguna otra forma de traducir un registro a un número único. Para obtener más información, investigue Hash Sorts, ya que eso es lo que es ...

Dave P.
fuente