Complejidad de std::list::splice y otros contenedores de lista


Tengo algún código que trata con varios objetos std::list, y actualmente estoy usando un método muy ineficiente de transferir contenido entre ellos (estoy iterando a través de secciones arbitrarias de una lista, y moviendo los elementos uno por uno a la segunda lista). Escribí este código hace algún tiempo antes de conocer la función std::list:: splice, con la que ahora pretendo reemplazar mi código, por ejemplo:

list<string> list1, list2;

list1.push_back("a");
list1.push_back("b");
list1.push_back("c"); // list1: "a", "b", "c"

list<string>::iterator iterator1 = list1.begin();
iterator1++: // points to "b"

list2.push_back("x");
list2.push_back("y");
list2.push_back("z"); // list2: "x", "y", "z"

list<string>::iterator iterator2 = list2.begin();
iterator2++; // points to "y"

list1.splice(iterator1, list2, iterator2, list2.end());

// list1: "a", "y", "z", "b", "c"
// list2: "x"

Tengo una pregunta con respecto a la complejidad de la función de empalme. Según esta fuente:

Http://www.cplusplus.com/reference/stl/list/splice /

Debe tener complejidad lineal en el rango entre el primer y el último elemento que se empalma (iterator2 y list2.end () en mi ejemplo), y la fuente sugiere que esto se debe al avance del iterador. Puedo vivir con esto, pero había estado esperando una complejidad constante.

Mi suposición (antes de encontrar esta fuente) era que la función de empalme hacer algo como esto:

  1. Cortar el vínculo entre "x" e "y"
  2. Cortar el vínculo entre "z" y list2.end ()
  3. Formar un vínculo entre "x" y list2.end ()
  4. Cortar el vínculo entre "a" y "b"
  5. Formar un vínculo entre" a "e"y"
  6. Formar un vínculo entre" y "y"b"

Restaurando así ambas listas a cadenas completas.

El mismo principio se aplicaría entonces a las listas de tamaño arbitrario. No estoy seguro de ver dónde hay la necesidad del empalme función para avanzar cualquier iteradores, ya que le estoy proporcionando todos los iteradores que necesita para hacer su trabajo.

Así que mi pregunta es, ¿cómo la especificación de C++ trata esto? ¿Rompe y vuelve a formar los enlaces solo en los puntos de inicio y final del empalme, o avanza a través de cada enlace uno por uno? Si es el último, ¿cualquier otro contenedor de la lista (por ejemplo, de QT) proporciona el primero? Mi código reside dentro del bucle interno de un programa de simulación, por lo que le da constante en lugar de la complejidad lineal sería muy valiosa.

Author: JBentley, 2012-04-13

1 answers

Este fue un tema muy polémico durante la estandarización de C++11. El problema es que todos los contenedores estándar, incluidas las listas, también tienen una operación de tiempo constante size.

Antes de C++11, muchas implementaciones hacían size tiempo lineal y splice entre diferentes listas de tiempo constante. C++11 ahora requiere que size sea constante y splice lineal.

El problema es que, si la longitud del rango empalmado no se cuenta uno por uno, entonces los contenedores no pueden realizar un seguimiento de cuántos elementos se eliminaron y agregaron, y la siguiente llamada a size necesitaría recuperar esta información en O(N) tiempo, utilizando el N más grande de toda la secuencia, no solo la parte empalmada.

Un contenedor no estándar list puede suministrar la operación deseada, porque mientras no necesite O(1) size, su argumento es correcto.

En cuanto a otras bibliotecas not no soy consciente de una, pero Boost debería tener una. (Lo comprobé,no lo hace, así que alguien vaya a empezar!) Dado que usted entiende claramente cómo escribir el suyo propio, hacerlo podría ser menos esfuerzo que lidiar con una biblioteca tan grande como Qt.

Si no necesita seguridad de subprocesos, podría implementar un wrapper alrededor de std::list en el que cada contenedor solo posee un subrango de una lista singleton. Esto eliminaría la mayor parte del esfuerzo de programación en la replicación de la interfaz estándar.

 28
Author: Potatoswatter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-13 03:42:37