2009-07-10 10 views
11

Pensé en la siguiente pregunta sobre la arquitectura de la computadora. Supongamos que yo hago en PythonRendimiento de la lista (...). Insertar (...)

from bisect import bisect 
index = bisect(x, a)  # O(log n) (also, shouldn't it be a standard list function?) 
x.insert(index, a)  # O(1) + memcpy() 

que tiene log n, además, si yo lo entiendo correctamente, una operación de copia de memoria para x[index:]. Ahora leí recientemente que el cuello de botella suele estar en la comunicación entre el procesador y la memoria, por lo que la copia de memoria podría ser hecha por RAM bastante rápido. ¿Es así como funciona?

Respuesta

13

Python es un idioma. Multiple implementations exist, y ellos pueden tienen implementaciones diferentes para las listas. Entonces, sin mirar el código de una implementación real, no se puede saber con certeza cómo se implementan las listas y cómo se comportan bajo ciertas circunstancias.

Mi apuesta sería que las referencias a los objetos en una lista se almacenan en la memoria contigua (ciertamente no como una lista vinculada ...). Si eso es así, entonces la inserción usando x.insert hará que se muevan todos los elementos detrás del elemento insertado. El hardware puede hacer esto de manera eficiente, pero la complejidad aún sería O (n).

Para listas pequeñas la operación bisect puede llevar más tiempo que x.insert, a pesar de que el primero es O (log n) mientras que el último es O (n). Para las listas largas, sin embargo, me arriesgaría a suponer que x.insert es el cuello de botella. En tales casos, debe considerar usar una estructura de datos diferente.

+0

Bueno, no estoy diciendo que memcpy() sea O (1) - Sé que es O (n), pero la constante puede ser pequeña, y no estoy seguro si está realmente optimizado por la memoria. Pero si está optimizado para ser, digamos, 1000 veces más rápido de lo que pensaría ingenuamente, eso probablemente sea algo que valga la pena saber. –

+0

En algunos casos, puede que no quede espacio en la lista, por lo que toda la lista debe copiarse después de asignar nueva memoria libre en lugar de solo memmove/memcpy. –

+0

La respuesta es válida, pero el primer párrafo no es necesariamente cierto en general. Un lenguaje puede especificar qué operaciones están diseñadas para ser eficientes en determinadas circunstancias, de modo que incluso sin mirar el código fuente de una implementación en particular, puede confiar en ciertas propiedades de rendimiento de esas operaciones, suponiendo que la implementación sea conforme. – LarsH

6

Las listas de CPython son matrices contiguas. Cuál de las inserciones O (log n) bisect y O (n) domina su perfil de rendimiento depende del tamaño de su lista y también de los factores constantes dentro de O(). Particularmente, la función de comparación invocada por bisect puede ser algo costoso dependiendo del tipo de objetos en la lista.

Si necesita mantener secuencias clasificables mutables potencialmente grandes, la matriz lineal subyacente al tipo de lista de pitones no es una buena opción. Dependiendo de sus montones de necesidades, los árboles o las listas de omisiones pueden ser apropiados.

9

Utilice blist module si necesita una lista con un mejor rendimiento de inserción.

Cuestiones relacionadas