C ++: contenedor secuencial

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
*/

Supongo que te gusta

Origin blog.csdn.net/m0_51354361/article/details/113823322
Recomendado
Clasificación