Notas de C ++: el quinto vector, es como una matriz pero no como una matriz

Tabla de contenido

1. Introducción y uso de vectores.

1 Introducción a los vectores 

2. El uso de vectores 

2.1 La definición de vector

2.2 Uso de iteradores vectoriales

2.3 Problema de crecimiento del espacio vectorial

2.4 Agregar, eliminar, verificar y modificar vectores 

2.5 Problema de invalidación del iterador de vectores 

Dos, análisis de profundidad vectorial

                1. Usa memcpy para copiar el problema 

2. Matriz bidimensional dinámica




1. Introducción y uso de vectores.



1 Introducción a los vectores


 1. Un vector es un contenedor de secuencias que representa una matriz de tamaño variable .


2. Al igual que una matriz, el vector también usa espacio de almacenamiento continuo para almacenar elementos. Eso significa que se puede acceder a los elementos del vector usando subíndices , que es tan eficiente como una matriz. Pero a diferencia de una matriz, su tamaño se puede cambiar dinámicamente y el contenedor manejará su tamaño automáticamente .


3. Esencialmente, vector usa una matriz asignada dinámicamente para almacenar sus elementos. Cuando se insertan nuevos elementos, es necesario cambiar el tamaño de la matriz para aumentar el espacio de almacenamiento. Lo hace asignando una nueva matriz y luego moviendo todos los elementos a esta matriz. En términos de tiempo, esta es una tarea relativamente costosa, porque el vector no cambia de tamaño cada vez que se agrega un nuevo elemento al contenedor.


4. Estrategia de asignación de espacio de Vector: Vector asignará algo de espacio adicional para acomodar un posible crecimiento, porque el espacio de almacenamiento es más grande que el espacio de almacenamiento real requerido. Diferentes bibliotecas emplean diferentes estrategias para sopesar el uso y la reasignación del espacio. Pero en cualquier caso, la reasignación debe ser de un tamaño de intervalo logarítmicamente creciente, de modo que la inserción de un elemento al final se realice en una complejidad de tiempo constante.


5. Por lo tanto, el vector ocupa más espacio de almacenamiento para obtener la capacidad de administrar el espacio de almacenamiento y crecer dinámicamente de manera eficiente.


6. En comparación con otros contenedores de secuencias dinámicas (deques, listas y listas de avance), el vector es más eficiente al acceder a los elementos, y agregar y eliminar elementos al final es relativamente eficiente. Para otras operaciones de eliminación e inserción que no están al final, es menos eficiente. Mejor que iteradores y referencias unificados para listas y listas de envío.


2. El uso de vectores


2.1 La definición de vector

declaración del constructor Descripción de la interfaz
vector() Sin construcción de parámetros
vector(tamaño_tipo n, constante valor_tipo& val = valor_tipo()) Construir e inicializar n vals
vector (const vector&x);  copiar construcción
vector (InputIterator primero, InputIterator último);  Inicializar la construcción usando iteradores

2.2 Uso de iteradores vectoriales

El uso de iteradores Descripción de la interfaz
comenzar()+finalizar()

obtener el iterador/const_iterator de la primera posición de datos,

Iterator/const_iterator para obtener la siguiente posición de los últimos datos

rbegin()+rend()

obtener el iterador inverso de la última posición de datos,

Obtenga el iterador inverso de la posición anterior de los primeros datos

void PrintVector(const vector<int>& v)
{
	// const对象使用const迭代器进行遍历打印
	vector<int>::const_iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}



vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);

vector<int>::iterator it = v.begin();
while (it != v.end())
{
	cout << *it << " ";
	++it;
}
cout << endl;

// 使用迭代器进行修改
it = v.begin();
while (it != v.end())
{
	*it *= 2;
	++it;
}

// 使用反向迭代器进行遍历再打印
vector<int>::reverse_iterator rit = v.rbegin();
while (rit != v.rend())
{
	cout << *rit << " ";
	++rit;
}
cout << endl;

2.3 Problema de crecimiento del espacio vectorial

espacio de capacidad Descripción de la interfaz
tamaño Obtener el número de datos
capacidad  Obtener el tamaño de la capacidad
vacío Determinar si está vacío.
cambiar el tamaño Cambiar el tamaño del vector
reservar Cambiar vector a capacidad

1. Cuando el código de capacidad se ejecuta bajo vs y g++ respectivamente, se encontrará que la capacidad bajo vs aumenta 1,5 veces y g++ aumenta 2 veces. vs es la versión STL de PJ, y g++ es la versión STL de SGI.


2. La reserva solo es responsable de abrir espacio. Si sabe cuánto espacio necesita, la reserva puede aliviar el defecto de costo de la expansión del vector.


3. El cambio de tamaño también se inicializará al abrir el espacio, lo que afectará el tamaño 

4. redimensionar: solo cambia el número de elementos, cuando el número de elementos excede el tamaño del espacio, amplía
   la reserva de capacidad: amplía la capacidad sin reducir el espacio

2.4 Agregar, eliminar, verificar y modificar vectores 

Agregar, eliminar, verificar y modificar vectores Descripción de la interfaz
hacer retroceder tapón de cola
pop_back eliminar cola
encontrar buscar
insertar  Insertar valor antes de la posición
borrar Eliminar los datos en la posición
intercambio  Intercambiar el espacio de datos de dos vectores.
operador[]  acceder como una matriz

¡Intenta ejecutar el siguiente código para ver el resultado!

pop_back, push_back

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	int a[] = { 1, 2, 3, 4 };
	vector<int> v(a, a + sizeof(a) / sizeof(int));
	vector<int>::iterator it = v.begin();
	while (it != v.end()) {
		cout << *it << " ";
		++it;
	}
	cout << endl;

	v.pop_back();
	v.pop_back();

    v.push_back(666);

	it = v.begin();
	while (it != v.end()) {
		cout << *it << " ";
		++it;
	}
	cout << endl;
	return 0;
}

 buscar, insertar, borrar

// find / insert / erase
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
	int a[] = { 1, 2, 3, 4 };
	vector<int> v(a, a + sizeof(a) / sizeof(int));
	// 使用find查找3所在位置的iterator
	vector<int>::iterator pos = find(v.begin(), v.end(), 3);

	// 在pos位置之前插入30
	v.insert(pos, 30);

	vector<int>::iterator it = v.begin();
	while (it != v.end()) {
		cout << *it << " ";
		++it;
	}
	cout << endl;
	pos = find(v.begin(), v.end(), 3);

	// 删除pos位置的数据
	v.erase(pos);

	it = v.begin();
	while (it != v.end()) {
		cout << *it << " ";
		++it;
	}
	cout << endl;
	return 0;
}

diferentes métodos transversales

// operator[]+index 和 C++11中vector的新式for+auto的遍历
// vector使用这两种遍历方式是比较便捷的。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
	int a[] = { 1, 2, 3, 4 };
	vector<int> v(a, a + sizeof(a) / sizeof(int));

	// 通过[]读写第0个位置。
	v[0] = 10;
	cout << v[0] << endl;

	// 通过[i]的方式遍历vector
	for (size_t i = 0; i < v.size(); ++i)
		cout << v[i] << " ";
	cout << endl;

	vector<int> swapv;
	swapv.swap(v);
	cout << "v data:";
	for (size_t i = 0; i < v.size(); ++i)
		cout << v[i] << " ";
	cout << endl;
	cout << "swapv data:";
	for (size_t i = 0; i < swapv.size(); ++i)
		cout << swapv[i] << " ";
	cout << endl;

	// C++11支持的新式范围for遍历
	for (auto x : v)
		cout << x << " ";
	cout << endl;
	return 0;
}

2.5 Problema de invalidación del iterador de vectores 

La función principal del iterador es permitir que el algoritmo no se preocupe por la estructura de datos subyacente. La capa subyacente es en realidad un puntero, o encapsula el puntero. Por ejemplo, el iterador de vector es el puntero original T* . Por lo tanto, la invalidación del iterador en realidad significa que el espacio al que apunta el puntero correspondiente en la parte inferior del iterador se destruye y se usa una parte del espacio que se ha liberado, lo que provoca un bloqueo del programa (es decir, si continúa usando el iterador inválido, el programa puede bloquearse).

(1) Las operaciones que causan cambios en el espacio subyacente pueden hacer que el iterador falle, como: redimensionar , reservar , insertar , asignar (la reasignación del vector puede hacer que la capacidad subyacente cambie v.assign(100, 8); ), retroceder , etc.

Solución : después de completar las operaciones anteriores, si desea continuar operando los elementos en el vector a través del iterador, solo necesita reasignar el iterador (aquí está)

while(it != v.end())
{
    cout<< *it << " " ;
    ++it;
}

(2) La operación de eliminación del elemento en la posición especificada --erase

Después de borrar borra el elemento en la posición pos, el elemento después de la posición pos avanzará sin causar ningún cambio en el espacio subyacente. Teóricamente hablando, el iterador no debería fallar, pero: si pos resulta ser el último elemento, después de la eliminación, pos pasa a ser la posición final, y la posición final no tiene elementos, entonces pos no será válido . Por lo tanto, al eliminar un elemento en cualquier posición del vector, vs considera que el iterador en esa posición no es válido 

Solución : simplemente reasigne el iterador antes de usarlo.



Dos, análisis de profundidad vectorial



1. Usa memcpy para copiar el problema 


1. memcpy es una copia de memoria en formato binario, que copia intacto el contenido de un espacio de memoria a otro espacio de memoria.
2. Si copia un elemento de un tipo personalizado, memcpy es eficiente y no tiene errores, pero si copia un elemento de un tipo personalizado y la administración de recursos está involucrada en el elemento del tipo personalizado, se producirá un error, porque el copy of memcpy En realidad es una copia superficial.

3. Si el objeto involucra la administración de recursos, no debe usar memcpy para copiar entre objetos, porque memcpy es una
copia superficial; de lo contrario, puede causar pérdidas de memoria o incluso bloqueos del programa.

¿Recuerdas la copia superficial y la copia profunda? Si no lo recuerda, vaya al artículo de cuerdas para echar un vistazo.

Aquí una breve mención:

Copia superficial: Los dos punteros p1 y p2 apuntan al mismo espacio, cuando se suelta p2, se borrará dos veces. Después de copiar, puede modificar el contenido en p1.

Copia profunda: p2 abre un nuevo espacio y copia el contenido en p1 a p2. Después de copiar, el contenido original en p1 no se modificará


2. Matriz bidimensional dinámica


vec.size()=行
vec[0].size()=列


(La imagen proviene de Internet) 

Supongo que te gusta

Origin blog.csdn.net/MuqiuWhite/article/details/129666909
Recomendado
Clasificación