2010-10-04 19 views
10

¿Cuál es la forma más rápida de ordenar una matriz de enteros enteros mayor que 0 y menos de 100000 en Python? Pero no usa las funciones integradas como ordenar.La forma más rápida de ordenar en Python

Estoy viendo la posibilidad de combinar 2 funciones deportivas dependiendo del tamaño de entrada.

+9

Por qué no utilizar construido en funciones? – MattH

+1

¿Cuál es la forma más rápida de llegar a la carretera pero sin conducir ese Porsche trucado? – aaronasterling

+0

¿Cuál es el tamaño más grande que podría tener la matriz? –

Respuesta

14

Si usted está interesado en tiempo asintótica, a continuación, contando tipo o especie radix proporcionar un buen rendimiento.

Sin embargo, si usted está interesado en pared del tiempo del reloj tendrá que comparar el rendimiento entre los diferentes algoritmos usando sus datos particular, establece, ya que diferentes algoritmos actúan de forma diferente con diferentes conjuntos de datos. En ese caso, su siempre vale la pena la clasificación rápida tratando:

def qsort(inlist): 
    if inlist == []: 
     return [] 
    else: 
     pivot = inlist[0] 
     lesser = qsort([x for x in inlist[1:] if x < pivot]) 
     greater = qsort([x for x in inlist[1:] if x >= pivot]) 
     return lesser + [pivot] + greater 

Fuente: http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Python versiones

+1

Un buen consejo, excepto la elección de la lista de variables, que puede causar buenos errores. Publiqué otra versión más rápida. –

+1

La ejecución de la lista de comprensión dos veces sobre el mismo conjunto de variables probablemente también sea menos que óptima. –

+2

@Tony Veijalainen "Solo hay dos cosas difíciles en informática: invalidación de caché y nombrar cosas" - Cambié el nombre de variable – fmark

7

Dado que conoce el rango de números, puede usar Counting Sort, que será lineal en el tiempo.

+3

(No he votado negativamente). Tenga en cuenta que este no es un buen algoritmo si la matriz de enteros es significativamente menor que 100000, ya que desperdiciará la memoria (y por lo tanto el tiempo) para construir la lista de 100000 elementos. – Brian

2

tempranos de Python utilizan un híbrido de samplesort (una variante de la clasificación rápida con el tamaño de la muestra) y binarios ordenación por inserción como el construido -in algoritmo de clasificación. Esto resultó ser algo inestable. S0, desde Python 2.3 en adelante usa el algoritmo adaptive mergesort.

Orden de mergesort (promedio) = O(nlogn). Orden de mergesort (peor) = O(nlogn). Pero Orden de ordenación rápida (el peor) = n * 2

si utiliza list=[ .............. ]

list.sort() utiliza mergesort algorithm.

Para la comparación entre el algoritmo de ordenación puede leer wiki

Para la comparación detalle comp

+0

es timsort que es más adaptable que mergesort – aaronasterling

+2

Timsort es un mergesort adaptativo, estable y natural. – Tauquir

1

Podemos usar la clasificación de recuento usando un diccionario para minimizar el uso de espacio adicional, y kee p el tiempo de funcionamiento bajo también. El tipo de recuento es mucho más lento para los tamaños pequeños de la matriz de entrada debido a la sobrecarga de implementación python vs C. El tipo de recuento comienza a superar el tipo normal cuando el tamaño de la matriz (COUNT) es aproximadamente 1 millón.

Si realmente desea grandes aceleraciones para entradas de menor tamaño, implemente la clasificación de conteo en C y llámelo de Python.

(Se ha corregido un error que Aaron (1) ayudó a la captura ...) La pitón única aplicación que sigue compara los enfoques 2 ...

import random 
import time 

COUNT = 3000000 

array = [random.randint(1,100000) for i in range(COUNT)] 
random.shuffle(array) 

array1 = array[:] 

start = time.time() 
array1.sort() 
end = time.time() 
time1 = (end-start) 
print 'Time to sort = ', time1*1000, 'ms' 

array2 = array[:] 

start = time.time() 
ardict = {} 
for a in array2: 
    try: 
     ardict[a] += 1 
    except: 
     ardict[a] = 1 

indx = 0 
for a in sorted(ardict.keys()): 
    b = ardict[a] 
    array2[indx:indx+b] = [a for i in xrange(b)] 
    indx += b 

end = time.time() 
time2 = (end-start) 
print 'Time to count sort = ', time2*1000, 'ms' 

print 'Ratio =', time2/time1 
+0

+1 'Ratio = 1.16710428623' en mi máquina. uso inteligente de un dict. Sin embargo, vale la pena señalar que al cambiar la fase de construcción del dict de 'try: ardict [a] + = 1; excepto: ardict [a] = 1' a 'if a in ardict: ardict [a] + = 1; else: ardict [a] = 1' reduce la relación a 'Ratio = 0.696179723863' A veces (a menudo) es mejor mirar antes de saltar. Sabía hacer esto porque 'try' es solo más barato que' if' si la excepción rara vez ocurre. Una excepción real sigue siendo muy costosa. – aaronasterling

+1

desafortunadamente este algoritmo es incorrecto. Pruebe 'array = [1,10, 100, 1000, 10000, 100000, 1000000]'. Los peligros de patinar en los detalles de implementación indocumentados vuelven a atacar. – aaronasterling

+0

Gracias aaron - corrigió el error de no ordenar las claves dict. Eso debería ralentizarlo un poco. Sin embargo, conservará su naturaleza casi O (n) si el número de elementos distintos en comparación con el tamaño de la matriz es bajo. Me encantaría ver una trama 3D de elementos distintos, la longitud de la matriz como dimensiones xey, la relación de tiempo de ejecución y la 3ª dimensión. Tal vez lo haga en un día o 2. – Rajan

3

Radix ordenaciones teóricamente en el tiempo lineal (tiempo de clase crece aproximadamente en proporción directa al tamaño de la matriz), pero en la práctica Quicksort es probablemente más adecuado, a menos que esté ordenando matrices absolutamente masivas.

Si desea hacer quicksort un poco más rápido, puede usar inserción sort] cuando el tamaño de la matriz se vuelve pequeño.

Probablemente sería útil comprender también los conceptos de complejidad algorítmica y notación Big-O.

+0

Cuando dice que el tamaño de la matriz se vuelve pequeño, ¿quiere decir que tiene menos de 64? – Anders

+0

Diría más acerca de menos de 10, pero no hay una respuesta correcta; la mejor idea es experimentar con diferentes valores y ver cuál termina más rápido. – Magnus

0
def sort(l): 
    p = 0 
    while(p<len(l)-1): 
     if(l[p]>l[p+1]): 
      l[p],l[p+1] = l[p+1],l[p] 
      if(not(p==0)): 
       p = p-1 
     else: 
      p += 1 
    return l 

este es un algoritmo que he creado pero que es muy rápido. simplemente haga una ordenación (l) siendo la lista que desea ordenar.

0

@fmark Algunos evaluación comparativa de una implementación de Python fusión-tipo que escribí contra quicksorts pitón de http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Python y de respuesta superior.

  1. tamaño de la lista y el tamaño de los números en la lista irrelevante

ordenamiento por mezcla gana, sin embargo, utiliza int orden interna() a baja

import numpy as np 
x = list(np.random.rand(100)) 


# TEST 1, merge_sort 
def merge(l, p, q, r): 
    n1 = q - p + 1 
    n2 = r - q 
    left = l[p : p + n1] 
    right = l[q + 1 : q + 1 + n2] 

    i = 0 
    j = 0 
    k = p 
    while k < r + 1: 
     if i == n1: 
      l[k] = right[j] 
      j += 1 
     elif j == n2: 
      l[k] = left[i] 
      i += 1 
     elif left[i] <= right[j]: 
      l[k] = left[i] 
      i += 1 
     else: 
      l[k] = right[j] 
      j += 1 
     k += 1 

def _merge_sort(l, p, r): 
    if p < r: 
     q = int((p + r)/2) 
     _merge_sort(l, p, q) 
     _merge_sort(l, q+1, r) 
     merge(l, p, q, r) 

def merge_sort(l): 
    _merge_sort(l, 0, len(l)-1) 

# TEST 2 
def quicksort(array): 
    _quicksort(array, 0, len(array) - 1) 

def _quicksort(array, start, stop): 
    if stop - start > 0: 
     pivot, left, right = array[start], start, stop 
     while left <= right: 
      while array[left] < pivot: 
       left += 1 
      while array[right] > pivot: 
       right -= 1 
      if left <= right: 
       array[left], array[right] = array[right], array[left] 
       left += 1 
       right -= 1 
     _quicksort(array, start, right) 
     _quicksort(array, left, stop) 

# TEST 3 
def qsort(inlist): 
    if inlist == []: 
     return [] 
    else: 
     pivot = inlist[0] 
     lesser = qsort([x for x in inlist[1:] if x < pivot]) 
     greater = qsort([x for x in inlist[1:] if x >= pivot]) 
     return lesser + [pivot] + greater 

def test1(): 
    merge_sort(x) 

def test2(): 
    quicksort(x) 

def test3(): 
    qsort(x) 

if __name__ == '__main__': 
    import timeit 
    print('merge_sort:', timeit.timeit("test1()", setup="from __main__ import test1, x;", number=10000)) 
    print('quicksort:', timeit.timeit("test2()", setup="from __main__ import test2, x;", number=10000)) 
    print('qsort:', timeit.timeit("test3()", setup="from __main__ import test3, x;", number=10000)) 
1

que podría ser un poco tarde para el programa, pero hay un artículo interesante que compara diferentes géneros en https://www.linkedin.com/pulse/sorting-efficiently-python-lakshmi-prakash

Uno de los principales puntos a tener en cuenta es que, aunque el tipo predeterminado Es genial que podemos hacerlo un poco mejor con una versión compilada de quicksort. Esto requiere el paquete Numba.

enter image description here

Aquí hay un enlace al repositorio de Github: https://github.com/lprakash/Sorting-Algorithms/blob/master/sorts.ipynb

Cuestiones relacionadas