[C++] El uso de lista enlazada (lista) y la diferencia con vector

1. Introducción a la lista

En C++, std::listes una clase contenedora proporcionada por la biblioteca estándar para el almacenamiento en cadena de datos. Una lista vinculada (lista) es una estructura de almacenamiento no continua en una unidad de almacenamiento física. El orden lógico de los elementos de datos se implementa a través de enlaces de puntero en la lista vinculada.

  • Composición de la lista enlazada: la lista enlazada consta de una serie de nodos .
  • La composición del nodo: 1. Campo de datos para almacenar elementos de datos 2. Campo de puntero para almacenar la dirección del siguiente nodo .

La lista vinculada en STL es una lista vinculada circular bidireccional . Dado que el método de almacenamiento de la lista vinculada no es un espacio de memoria continuo, el iterador en la lista vinculada solo admite movimientos hacia adelante y hacia atrás y es un iterador bidireccional .


2. La diferencia entre std::list y std::vector

  1. Implementación de bajo nivel:

    • listSe implementa mediante una lista doblemente enlazada, cada elemento contiene punteros al elemento anterior y siguiente. Esta implementación hace que la inserción y eliminación de elementos en cualquier lugar de la lista sea eficiente, pero tiene un rendimiento deficiente para el acceso aleatorio a los elementos.
    • vectorSe implementa mediante una matriz dinámica y los elementos se almacenan continuamente en la memoria. Esta implementación hace que el rendimiento del acceso aleatorio a elementos sea muy bueno, pero insertar/eliminar elementos en el medio o al principio implica mover elementos y el rendimiento es relativamente bajo.
  2. Cambio de tamaño dinámico:

    • listEl tamaño de puede crecer y reducirse dinámicamente porque utiliza una lista vinculada para almacenar elementos, y el rendimiento de las operaciones de inserción y eliminación es independiente del tamaño de la lista.
    • vectorEl tamaño también puede crecer dinámicamente, pero esto puede resultar en una gran cantidad de operaciones de copia de elementos y reasignación de memoria cuando es necesario reasignar la memoria.
  3. Eficiencia de acceso:

    • listNo se admite el acceso aleatorio, solo el acceso secuencial mediante iteradores. Para escenarios que requieren operaciones frecuentes de inserción y eliminación, listel rendimiento es mejor.
    • vectorAdmite acceso aleatorio, se puede acceder a los elementos directamente a través de subíndices. Para operaciones que requieren acceso aleatorio frecuente, vectorel rendimiento es mejor.
  4. Uso de memoria:

    • listAl almacenar elementos, además del valor del elemento en sí, se requiere espacio adicional para almacenar punteros a los elementos anterior y siguiente. Por lo tanto, suele vectorutilizar más memoria que .
    • vectorAl almacenar un elemento, solo es necesario almacenar el valor del elemento en sí y alguna información de control adicional, por lo que generalmente usa listmenos memoria que .
  5. Operaciones de inserción y eliminación:

    • listEs eficiente para insertar y eliminar elementos en posiciones arbitrarias porque solo requiere modificar los punteros de elementos adyacentes y no requiere mover otros elementos. listHay una propiedad importante: ni las operaciones de inserción ni de eliminación harán que el iterador de la lista original deje de ser válido. Esto vectorno es cierto en .
    • vectorEs eficiente para insertar y eliminar elementos al final porque solo necesita operar al final de la matriz y no requiere mover otros elementos. Pero al insertar/eliminar elementos en el medio o al principio, es necesario mover otros elementos.

En resumen, la elección de utilizar listo vectordepende de los escenarios y necesidades de aplicación específicos. Puede elegir esto si se requieren operaciones frecuentes de inserción y eliminación y no se requiere acceso aleatorio frecuente a elementos list. Si necesita acceso aleatorio frecuente a elementos y menos operaciones de inserción y eliminación, puede elegirlo vector. Además, si necesita realizar operaciones de inserción y eliminación en el medio del contenedor y la eficiencia del acceso no es alta, puede considerar usarlo list.


3. Constructor de listas

Prototipo constructor explicar
1 lista<T> lt Constructor predeterminado, implementado mediante clases de plantilla.
2 lista(lt.begin(), lt.end()) Copie los elementos en el intervalo lt[begin, end) a sí mismo
3 lista(n, Elemento) El constructor copia n elementos a sí mismo.
4 lista (lista constante <) constructor de copias

Ejemplo:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void printVec(list<int> &v)
{
    
    
	for (list<int>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}
void printVec(list<double> &v)
{
    
    
	for (list<double>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
    
    
	list<int> v1;
	v1.push_back(10);  //添加元素
	v1.push_back(20);
	printVec(v1);

	list<int> v2(v1.begin(), v1.end());
	printVec(v2);

	list<double> v3(5, 6.32);
	printVec(v3);

	list<double> v4(v3);
	printVec(v4);
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
10 20
10 20
6.32 6.32 6.32 6.32 6.32
6.32 6.32 6.32 6.32 6.32

Aviso:

Cuando la lista se utiliza como parámetro o valor de retorno de una función, no puede faltar el "&".


4. Asignación de lista

Prototipo de función: =, asignar explicar
1 lista& operador=(lista constante <) Sobrecargado = operador
2 asignar (comienzo, fin) Copie y asigne los datos en el intervalo [comienzo, fin) a sí mismo
3 asignar(n, Elemento) Asignar n copias de elementos a sí mismo

Ejemplo:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void printVec(list<int> &v)
{
    
    
	for (list<int>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
    
    
	list<int> v1;
	v1.push_back(10);  //添加元素
	v1.push_back(20);
	printVec(v1);

	list<int> v2 = v1;
	printVec(v2);

	list<int> v3;
	v3.assign(v1.begin(), v1.end());
	printVec(v3);

	list<int> v4;
	v4.assign(6, 1);
	printVec(v4);
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
10 20
10 20
10 20
1 1 1 1 1 1

5. Operación de longitud de lista

Prototipo de función: vaciar, dimensionar, cambiar tamaño explicar
1 vacío() Determinar si el contenedor está vacío.
2 tamaño() Devuelve el número de elementos en el contenedor.
3 cambiar tamaño(int núm) Vuelva a especificar la longitud del contenedor a num. Si el contenedor se alarga, la nueva posición se llena con el valor predeterminado; si el contenedor se acorta, los elementos al final que exceden la longitud del contenedor se eliminan.
4 cambiar tamaño(int num, Elemento) Vuelva a especificar la longitud del contenedor a num. Si el contenedor se alarga, la nueva posición se llena con el valor del Elemento; si el contenedor se acorta, los elementos al final que excedan la longitud del contenedor se eliminan.

Ejemplo:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void printVec(list<int> &v)
{
    
    
	for (list<int>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
    
    
	list<int> v1;
	if (v1.empty())     //判断是否为空
	{
    
    
		cout << "当前v1为空!" << endl;
	}

	v1.push_back(10);  //添加元素
	v1.push_back(20);
	v1.push_back(30);

	if (!v1.empty())
	{
    
    
		cout << "v1中元素个数:" << v1.size() << endl;
		printVec(v1);
	}

	v1.resize(5);
	printVec(v1);

	v1.resize(10, 1);
	printVec(v1);
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
当前v1为空!
v1中元素个数:3
10 20 30
10 20 30 0 0
10 20 30 0 0 1 1 1 1 1

6. Inserción y eliminación de listas

Prototipo de función: push_back, pop_back, insertar, borrar, borrar explicar
1 push_back(Elemento) Insertar elemento al final
2 pop_back() Eliminar el último elemento
3 push_front(Elemento) Insertar un elemento al principio del contenedor.
4 pop_front() Retire el primer elemento del comienzo del contenedor.
5 insertar(iterador p, Elemento) El iterador apunta a la posición p para insertar el elemento Elemento
6 insertar(iterador p, int n, Elemento) El iterador apunta a la posición p e inserta n elementos Elemento
7 insertar(p,inicio del iterador,fin del iterador) Inserte datos en el intervalo [inicio, fin) en la posición p, sin valor de retorno
8 borrar (iterador p) Eliminar el elemento señalado por el iterador.
9 borrar (inicio del iterador, final del iterador) Eliminar los elementos de principio a fin del iterador.
10 eliminar (elemento) Eliminar todos los elementos en el contenedor que coincidan con el valor del elemento
11 claro() Eliminar todos los elementos del contenedor.

Ejemplo:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void printVec(list<int> &v)
{
    
    
	for (list<int>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
    
    
	list<int> v1;
	v1.push_back(1);  //尾部添加元素
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(3);
	cout << "尾部添加元素: " << endl;
	printVec(v1);

	v1.pop_back();    //尾部删除元素
	cout << "尾部删除元素: " << endl;
	printVec(v1);

	v1.push_front(100);  //头部添加元素
	v1.push_front(200);
	v1.push_front(300);
	cout << "头部添加元素: " << endl;
	printVec(v1);

	v1.pop_front();   //头部删除元素
	v1.pop_front();
	cout << "头部删除元素: " << endl;
	printVec(v1);

	v1.insert(v1.begin(), 100);      //插入元素100
	cout << "插入元素100: " << endl;
	printVec(v1);

	v1.insert(v1.begin(), 5, 100);   //插入5个元素100
	cout << "插入5个元素100: " << endl;
	printVec(v1);

	v1.erase(v1.begin());    //删除元素
	cout << "删除元素v1.begin(): " << endl;
	printVec(v1);

	v1.remove(100);
	cout << "删除所有100元素: " << endl;
	printVec(v1);

	v1.clear();				 //清空容器
	printVec(v1);
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
尾部添加元素:
1 2 3 3
尾部删除元素:
1 2 3
头部添加元素:
300 200 100 1 2 3
头部删除元素:
100 1 2 3
插入元素100:
100 100 1 2 3
插入5个元素100:
100 100 100 100 100 100 100 1 2 3
删除元素v1.begin():
100 100 100 100 100 100 1 2 3
删除所有100元素:
1 2 3

7. Adquisición de datos de lista

Prototipo de función: frente (), atrás explicar
1 frente() Devuelve el primer elemento de datos en el contenedor.
2 atrás() Devuelve el último elemento de datos en el contenedor.

Ejemplo:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void test01()
{
    
    
	list<int> v1 = {
    
     1, 2, 3, 4, 5, 6 };
	cout << "v1.front() = " << v1.front() << endl;
	cout << "v1.back() = " << v1.back() << endl;
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
v1.front() = 1
v1.back() = 6

8. Intercambio, reversión y clasificación de listas.

Prototipo de función: intercambiar, invertir, ordenar explicar
1 intercambiar (lista lt) Intercambia los elementos en lt con sus propios elementos.
2 contrarrestar() Lista enlazada inversa
3 clasificar() Clasificación de listas enlazadas

Ejemplo:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void printVec(list<int> &v)
{
    
    
	for (list<int>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
    
    
	list<int> v1 = {
    
     9, 5, 7, 8, 6 };
	list<int> v2 = {
    
     5, 4, 3, 2, 1 };

	v1.swap(v2);   //互换v1与v2中的元素
	cout << "list v1 : " ;
	printVec(v1);
	cout << "list v2 : " ;
	printVec(v2);

	v2.sort();  //链表排序
	cout << "v2链表排序 : ";
	printVec(v2);

	v2.reverse();  //反转链表v2
	cout << "v2反转链表 : ";
	printVec(v2);
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
list v1 : 5 4 3 2 1
list v2 : 9 5 7 8 6
v2链表排序 : 5 6 7 8 9
v2反转链表 : 9 8 7 6 5

Si este artículo te resulta útil, ¡me gustaría recibir un Me gusta tuyo!

Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/AAADiao/article/details/131214952
Recomendado
Clasificación