Contenedor secuencial
-
Vector
-
Deque
-
Lista
-
Lista enlazada individualmente (forward_list) (los cuatro anteriores se pueden considerar como una matriz con una longitud expandible lógicamente)
-
Formación
-
Los elementos se organizan linealmente y puede insertar y eliminar elementos en la posición especificada en cualquier momento.
-
Debe ajustarse al concepto de Asignable (es decir, tiene un constructor de copia público y puede asignarse con "=").
-
El tamaño del objeto de matriz es fijo y forward_list tiene operaciones especiales de adición y eliminación.
Interfaz de contenedor secuencial (no incluye lista enlazada individualmente (forward_list) y matriz (matriz))
-
Constructor
-
Función de asignación
- asignar
-
Función de inserción
- insert, pushfront (solo para lista y deque), pushback, emplace, emplace_front
-
Función de eliminación
- borrar, borrar, popfront (solo para lista y deque), popback, emplace_back
-
Acceso directo a los primeros y últimos elementos
- frente atrás
-
Cambiar tamaño
- cambiar el tamaño
Operación básica de contenedor secuencial
#include <iostream>
#include <list>
#include <deque>
using namespace std;
//输出指定的顺序容器的元素
template <class T>
void printContainer(const char* msg, const T& s) {
cout << msg << ": ";
copy(s.begin(), s.end(), ostream_iterator<int>(cout, " "));
cout << endl;
}
int main() {
//从标准输入读入10个整数,将它们分别从s的头部加入
deque<int> s;
for (int i = 0; i < 10; i++) {
int x;
cin >> x;
s.push_front(x);
}
printContainer("deque at first", s);
//用s容器的内容的逆序构造列表容器l
list<int> l(s.rbegin(), s.rend());
printContainer("list at first", l);
//将列表容器l的每相邻两个元素顺序颠倒
list<int>::iterator iter = l.begin();
while (iter != l.end()) {
int v = *iter;
iter = l.erase(iter);
l.insert(++iter, v);
}
printContainer("list at last", l);
//用列表容器l的内容给s赋值,将s输出
s.assign(l.begin(), l.end());
printContainer("deque at last", s);
return 0;
}
/*
运行结果如下:
0 9 8 6 4 3 2 1 5 4
deque at first: 4 5 1 2 3 4 6 8 9 0
list at first: 0 9 8 6 4 3 2 1 5 4
list at last: 9 0 6 8 3 4 1 2 4 5
deque at last: 9 0 6 8 3 4 1 2 4 5
/*
Características de los contenedores secuenciales
-
Contenedor de secuencia: vector, deque, lista, lista enlazada individualmente, matriz
-
Vector
-
Capacidad (capacidad): el tamaño del espacio asignado real
-
s.capacity (): devuelve la capacidad actual
-
s.reserve (n): Si la capacidad es menor que n, expanda s para que su capacidad sea al menos n
-
Una matriz dinámica que se puede expandir
-
Acceso aleatorio, insertar o eliminar elementos al final rápidamente
-
Insertar o eliminar elementos en el medio o el encabezado es lento
-
Características
-
-
Capacidad vectorial
-
Deque
-
Inserte o elimine elementos en ambos extremos rápidamente
-
Insertar o eliminar elementos en el medio es lento
-
El acceso aleatorio es más rápido, pero más lento que los contenedores vectoriales
-
Características
-
Orden de paridad
#include<iostream>
#include<vector>
#include<deque>
#include<algorithm>
#include<iterator>
using namespace std;
int main() {
istream_iterator<int> i1(cin), i2; //建立一对输入流迭代器
vector<int> s1(i1, i2); //通过输入流迭代器从标准输入流中输入数据
sort(s1.begin(), s1.end()); //将输入的整数排序
deque<int> s2;
//以下循环遍历s1
for (vector<int>::iterator iter = s1.begin(); iter != s1.end(); ++iter)
{
if (*iter % 2 == 0) //偶数放到s2尾部
s2.push_back(*iter);
else //奇数放到s2首部
s2.push_front(*iter);
}
//将s2的结果输出
copy(s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
Lista
-
Características
-
Insertar y eliminar elementos en cualquier posición es rápido
-
No admite acceso aleatorio
-
-
Operación de empalme
- s1.splice (p, s2, q1, q2): Mueva [q1, q2) en s2 antes del elemento apuntado por p en s1
#include<iostream>
#include<string>
#include<list>
#include<iterator>
using namespace std;
int main() {
string names1[] = {
"Alice", "Helen", "Lucy", "Susan" };
string names2[] = {
"Bob", "David", "Levin", "Mike" };
//用names1数组的内容构造列表s1
list<string> s1(names1, names1 + 4);
//用names2数组的内容构造列表s2
list<string> s2(names2, names2 + 4);
//将s1的第一个元素放到s2的最后
s2.splice(s2.end(), s1, s1.begin());
list<string>::iterator iter1 = s1.begin(); //iter1指向s1首
advance(iter1, 2); //iter1前进2个元素,它将指向s1第3个元素
list<string>::iterator iter2 = s2.begin(); //iter2指向s2首
++iter2; //iter2前进1个元素,它将指向s2第2个元素
list<string>::iterator iter3 = iter2; //用iter2初始化iter3
advance(iter3, 2); //iter3前进2个元素,它将指向s2第4个元素
//将[iter2, iter3)范围内的结点接到s1中iter1指向的结点前
s1.splice(iter1, s2, iter2, iter3);
//分别将s1和s2输出
copy(s1.begin(), s1.end(), ostream_iterator<string>(cout, " "));
cout << endl;
copy(s2.begin(), s2.end(), ostream_iterator<string>(cout, " "));
cout << endl;
return 0;
}
Lista individualmente vinculada (forward_list)
-
Cada nodo de la lista enlazada individualmente solo tiene un puntero al siguiente nodo, y no hay una manera fácil de obtener el predecesor de un nodo;
-
Las operaciones insertar, ubicar y borrar no están definidas, pero las operaciones insertar después, emplaceafter y erase_after están definidas. Los parámetros son los mismos que para insertar, ubicar y borrar la lista, pero en lugar de insertar o eliminar el elemento señalado a por el iterador p1, es para p1 Se refiere al nodo después del elemento a operar;
-
No se admite la operación de tamaño.
Formación
-
Array es una encapsulación de la matriz incorporada, que proporciona una forma más segura y conveniente de utilizar la matriz.
-
El tamaño del objeto de la matriz es fijo. Además de especificar el tipo de elemento, también debe especificar el tamaño del contenedor al definirlo.
-
No se puede cambiar dinámicamente el tamaño del contenedor
Comparación de contenedores secuenciales
-
Los contenedores secuenciales proporcionados por STL tienen sus propias fortalezas y debilidades Al escribir programas, debemos decidir qué contenedor elegir en función de las operaciones que necesitamos realizar en el contenedor.
-
Si necesita realizar muchas operaciones de acceso aleatorio, y solo necesita agregar nuevos elementos al final del contenedor al expandir el contenedor, debe elegir el vector contenedor vector;
-
Si necesita una pequeña cantidad de operaciones de acceso aleatorio, necesita insertar o eliminar elementos en ambos extremos del contenedor, debe elegir la deque de la deque;
-
Si no necesita realizar un acceso aleatorio al contenedor, pero necesita insertar o eliminar elementos en la posición media, debe elegir la lista de contenedores list o forward_list;
-
Si necesita una matriz, la matriz es un tipo de matriz más seguro y fácil de usar en comparación con el tipo de matriz incorporado.
Insertar iteradores y adaptadores para contenedores secuenciales
Insertar iterador para contenedores secuenciales
-
Iterador para insertar elementos en la posición especificada en la cabeza, cola o centro del contenedor
-
Incluyendo frontinserter (frontinserter), backinserter (backinsrter) e iterador de inserción de posición arbitraria (insertador)
list<int> s;
back_inserter iter(s);
*(iter++) = 5; //通过iter把5插入s末尾
Adaptador de contenedor de secuencia
Algunas estructuras de datos de uso común se construyen en base a contenedores secuenciales, que son la encapsulación de contenedores secuenciales.
-
Pila: el elemento que se empujó primero es el último en aparecer
-
Cola (cola): el elemento que se presiona primero es el primero en aparecer
-
Cola de prioridad (priority_queue): el elemento "más grande" es el primero en aparecer
Plantillas de pila y cola
- Plantilla de pila
template <class T, class Sequence = deque<T> > class stack;
- Plantilla de cola
template <class T, class FrontInsertionSequence = deque<T> > class queue;
- La pila puede usar cualquier tipo de contenedor secuencial como contenedor básico, y la cola solo permite el uso del contenedor preinsertado (lista o cola de dos extremos)
Operaciones admitidas por pila y cola
-
s1 op s2 op puede ser uno de ==,! =, <, <=,>,> =, comparará los elementos entre los dos adaptadores de contenedor en orden lexicográfico
-
s.size () devuelve el número de elementos en s
-
s.empty () devuelve si s está vacío
-
s.push (t) empuja el elemento t hacia s
-
s.pop () saca un elemento de s. Para la pila, el elemento que se empuja cada vez es el último elemento que se empuja, y para la cola, el elemento que se empuja cada vez es el elemento que se empuja primero.
-
Los iteradores no son compatibles porque no permiten el acceso a elementos arbitrarios.
Diferentes operaciones en pila y cola
Operación de pila
- s.top () devuelve una referencia al elemento superior de la pila
Operación en cola
-
s.front () Obtiene una referencia al elemento head
-
s.back () Obtiene la referencia del elemento tail
Utilice la pila para invertir las palabras de salida
#include<iostream>
#include<stack>
#include<string>
using namespace std;
int main() {
stack<char> s;
string str;
cin >> str; //从键盘输入一个字符串
//将字符串的每个元素顺序压入栈中
for (string::iterator iter = str.begin(); iter != str.end(); ++iter)
s.push(*iter);
//将栈中的元素顺序弹出并输出
while (!s.empty()) {
cout << s.top();
s.pop();
}
cout << endl;
return 0;
}
/*运行结果如下:
congratulations
snoitalutargnoc*/
Cola de prioridad
- Las colas de prioridad también admiten el empuje y el estallido de elementos como pilas y colas, pero el orden en el que se colocan los elementos está relacionado con el tamaño de los elementos, y cada pop es siempre el elemento "más grande" del contenedor.
template <class T, class Sequence = vector<T> > class priority_queue;
-
El contenedor básico de la cola de prioridad debe ser un contenedor secuencial que admita el acceso aleatorio.
-
Admite varias funciones miembro de pila y cola, tamaño, vacío, empujar y pop, y el uso es el mismo que pila y cola.
-
Las colas de prioridad no admiten operaciones de comparación.
-
Similar a la pila, la cola de prioridad proporciona una función superior para obtener una referencia al siguiente elemento que se va a extraer (es decir, el elemento "más grande").
Simulación de división
celular Una célula se dividirá en dos células dentro de los 500 a 2000 segundos después del nacimiento (es decir, la última división), y cada célula continuará dividiéndose de acuerdo con la misma ley.
#include<iostream>
#include<queue>
using namespace std;
const int SPLIT_TIME_MIN = 500; //细胞分裂最短时间
const int SPLIT_TIME_MAX = 2000; //细胞分裂最长时间
class Cell;
priority_queue<Cell> cellQueue;
class Cell {
//细胞类
private:
static int count; //细胞总数
int id; //当前细胞编号
int time; //细胞分裂时间
public:
Cell(int birth) : id(count++) {
//birth为细胞诞生时间
//初始化,确定细胞分裂时间
time = birth + (rand() % (SPLIT_TIME_MAX - SPLIT_TIME_MIN))+ SPLIT_TIME_MIN;
}
int getId() const {
return id; } //得到细胞编号
int getSplitTime() const {
return time; } //得到细胞分裂时间
bool operator < (const Cell& s) const //定义“<”
{
return time > s.time; }
void split() {
//细胞分裂
Cell child1(time), child2(time); //建立两个子细胞
cout << time << "s: Cell #" << id << " splits to #" << child1.getId() << " and #" << child2.getId() << endl;
cellQueue.push(child1); //将第一个子细胞压入优先级队列
cellQueue.push(child2); //将第二个子细胞压入优先级队列
}
};
int Cell::count = 0;
int main() {
srand(static_cast<unsigned>(time(0)));
int t; //模拟时间长度
cout << "Simulation time: ";
cin >> t;
cellQueue.push(Cell(0)); //将第一个细胞压入优先级队列
while (cellQueue.top().getSplitTime() <= t) {
cellQueue.top().split(); //模拟下一个细胞的分裂
cellQueue.pop(); //将刚刚分裂的细胞弹出
}
return 0;
}
/*
运行结果如下:
Simulation time: 5000
971s: Cell #0 splits to #1 and #2
1719s: Cell #1 splits to #3 and #4
1956s: Cell #2 splits to #5 and #6
2845s: Cell #6 splits to #7 and #8
3551s: Cell #3 splits to #9 and #10
3640s: Cell #4 splits to #11 and #12
3919s: Cell #5 splits to #13 and #14
4162s: Cell #10 splits to #15 and #16
4197s: Cell #8 splits to #17 and #18
4317s: Cell #7 splits to #19 and #20
4686s: Cell #13 splits to #21 and #22
4809s: Cell #12 splits to #23 and #24
4818s: Cell #17 splits to #25 and #26
*/