C++ STL cola bidireccional deque explicación detallada

Parte I Atención

inserte la descripción de la imagen aquí

  • Deque es la abreviatura de cola de doble extremo, lo que significa cola de doble extremo. Para obtener más información, consulte el sitio web oficial .
  • deque<T>El adaptador del contenedor es
  • el archivo de encabezado debe ser incluido#include <deque>
  • dequeEn comparación con vector: ① no es bueno para agregar y eliminar elementos en el medio; ② es bueno para agregar y eliminar elementos al principio y al final de la cola, la complejidad de tiempo es , y solo la complejidad de tiempo de agregar y O(1)eliminar vectorelementos en la cola es O(1).
  • dequeComparado con queue: queue solo es bueno para eliminar elementos en la cabeza y agregar elementos al final; mientras que deque es bueno para agregar o eliminar elementos tanto en la cabeza como en la cola.
  • La cola bidireccional de C++ no se usa mucho y, por lo general, se usa para responder preguntas vector. Pero también es una estructura de datos típica en STL, por lo que también se puede considerar en la producción real.

Parte II Función

dequeLa función de es queuemucho más que la de , y Vectores equivalente, como se muestra en la siguiente figura:

inserte la descripción de la imagen aquí

La siguiente es una descripción de las funciones comúnmente utilizadas:

función explicar
begin() iterador de inicio
end() iterador final
rbegin() iterador comenzando en reversa
rend() iterador con final inverso
size() Contiene el número de elementos.
max_size El número máximo de elementos que se pueden acomodar
resize() redimensionarlo
empty() Comprobar si está vacío
front() elemento más al frente
back() último elemento
assign() Se le puede asignar a través de una matriz.
push_back() Añadir un elemento al final de la deque
push_front() Agregar un elemento al frente del deque
pop_back() Pop el último elemento de la cola de dos extremos
pop_front() Pop el primer elemento de la cola de dos extremos
insert() Insertar elementos, hay varios usos
erase(d.begin(),d.begin()+3) eliminar los primeros 3 elementos
a.swap(b) intercambio ayb
clear() borrar todos los elementos
emplace(itr,a) itrInserte un elemento antes de la posición del iterador a, el aiterador devuelto
emplace_front() insertar elemento antes
emplace_back() insertar elemento después

Parte III Código

A continuación , se presenta el uso de colas de dos extremos en función de una pregunta de programación en LeetCode Sword Pointer Offer II 026. Reorganizar la lista enlazada .

Cap.I descripción y análisis del tema

Tema Descripción

Dada la cabeza del nodo principal de una lista L unida, la lista L unida se expresa como:
L0 → L1 → … → Ln-1 → Ln

Reorganícelo para que se convierta en:
L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …

No puede simplemente cambiar el valor dentro del nodo, sino que necesita intercambiar el nodo.


analizar

De acuerdo con el significado de la pregunta, la lista enlazada original debe reorganizarse de forma escalonada; el autor pensó inmediatamente en una cola de dos extremos, y la idea es la siguiente:

  • Primero recorra la lista enlazada original en un lado y almacene todos los nodos en la cola de dos extremos
  • Luego toma uno de la cabeza y otro de la cola en secuencia.
  • hasta que no haya más nodos en la cola.
  • Complejidad del tiempo O(n)Complejidad del espacioO(n)

Implementación del código Cap.II

C++código deque .

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    
    
public:
    void reorderList(ListNode* head) {
    
    
        deque<ListNode*> dqu;
        while(head) {
    
    
            dqu.emplace_back(head);
            head=head->next;
        }
        ListNode* pre=nullptr;
        while(dqu.size()>=2) {
    
    
            if(!pre) {
    
    
                pre=dqu.front();
            }
            else {
    
    
                pre->next=dqu.front();
                pre=pre->next;
            }
            pre->next=dqu.back();
            pre=pre->next;
            dqu.pop_front();dqu.pop_back();
        }
        if(!dqu.empty()) {
    
    
            if(!pre) pre=dqu.front();
            else {
    
    
                pre->next=dqu.front();
                pre=pre->next;
            }
        }
        pre->next=nullptr;
    }
};

Se puede usar como ejemplo del uso de una cola de dos extremos, pero para esta pregunta, usar una cola de dos extremos no es necesariamente la solución óptima.

Cap.III Dos formas de resolver problemas

La siguiente forma de pensar es más eficiente:

  • Use dos punteros, uno es un puntero rápido (dos nodos a la vez) y el otro es un puntero lento (un nodo a la vez); el puntero lento voltea la lista vinculada mientras camina y usa uno como variable intermedia pre.
  • Cuando todos los punteros rápidos llegan al final de la lista enlazada, el puntero rápido solo apunta a la mitad de la lista enlazada
  • En este momento, el puntero rápido apunta prey el puntero lento continúa moviéndose hacia adelante, y los resultados se pueden cruzar mientras se camina.

La siguiente es la implementación del código (es un poco complicado de escribir)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    
    
public:
    void reorderList(ListNode* head) {
    
    
        if(!head||!head->next) return;
        int tag=0;      // 针对节点个数奇偶涉及的标识 奇1偶0
        ListNode* slow=head, *fast=head, *pre=nullptr;
        while(fast) {
    
    
            if(fast->next) {
    
    
                fast=fast->next;
                ListNode* tmp=slow->next;
                slow->next=pre; pre=slow;
                slow=tmp;
            }
            else {
    
     tag=1; break; }
            if(fast->next) {
    
    
                fast=fast->next;
            }
            else break;
        }
        fast=nullptr;
        head=slow; // slow 就是中点
        slow=slow->next;
        head->next=fast;
        if(tag) {
    
     fast=slow; slow=slow->next; fast->next=head; head=fast; }
        while(slow) {
    
    
            fast=pre; pre=pre->next; fast->next=head; head=fast;
            fast=slow; slow=slow->next; fast->next=head; head=fast;
        }
        if(pre) pre->next=head; head=pre;
    }
};

Implementación de la cola de dos extremos de la Parte IV

La siguiente parte es la idea de implementación subyacente de la cola de dos extremos, tomando el tema de LeetCode 641. Diseñar una cola circular de dos extremos como ejemplo.

Cap.I Título Descripción

Bajo la premisa de no utilizar dequeclases, el diseño implementa colas de dos extremos.

Implemente la clase MyCircularDeque:

  • MyCircularDeque(int k): Constructor, la cola de dos extremos es como máximo k.
  • boolean insertFront(): Añade un elemento a la cabecera del deque. Devuelve verdadero si la operación fue exitosa, falso en caso contrario.
  • boolean insertLast(): agregue un elemento a la cola de la cola doble. Devuelve verdadero si la operación fue exitosa, falso en caso contrario.
  • boolean deleteFront(): elimina un elemento de la cabeza de la cola doble. Devuelve verdadero si la operación fue exitosa, falso en caso contrario.
  • boolean deleteLast(): elimina un elemento de la cola de la cola doble. Devuelve verdadero si la operación fue exitosa, falso en caso contrario.
  • int getFront(): Obtener un elemento de la cabeza de la cola doble. Devuelve -1 si el deque está vacío.
  • int getRear(): Obtiene el último elemento de la cola doble. Devuelve -1 si el deque está vacío.
  • boolean isEmpty(): Devuelve verdadero si la cola doble está vacía; de lo contrario, devuelve falso.
  • boolean isFull(): si la cola de dos extremos está llena, devuelve verdadero; de lo contrario, devuelve falso.

Implementación del código Cap.II

Esta pregunta es muy similar a la 662. Diseño de una cola circular . Puedes ver la solución

#include <iostream>
#include <vector>

using namespace std;

class MyCircularDeque {
    
    

private:
    vector<int> arr;
    int front;
    int rear;
    int capacity;

public:
    /** Initialize your data structure here. Set the size of the deque to be k. */
    MyCircularDeque(int k) {
    
    
        capacity = k + 1;
        arr.assign(capacity, 0);

        front = 0;
        rear = 0;
    }

    /** Adds an item at the front of Deque. Return true if the operation is successful. */
    bool insertFront(int value) {
    
    
        if (isFull()) {
    
    
            return false;
        }
        front = (front - 1 + capacity) % capacity;
        arr[front] = value;
        return true;
    }

    /** Adds an item at the rear of Deque. Return true if the operation is successful. */
    bool insertLast(int value) {
    
    
        if (isFull()) {
    
    
            return false;
        }
        arr[rear] = value;
        rear = (rear + 1) % capacity;
        return true;
    }

    /** Deletes an item from the front of Deque. Return true if the operation is successful. */
    bool deleteFront() {
    
    
        if (isEmpty()) {
    
    
            return false;
        }
        // front 被设计在数组的开头,所以是 +1
        front = (front + 1) % capacity;
        return true;
    }

    /** Deletes an item from the rear of Deque. Return true if the operation is successful. */
    bool deleteLast() {
    
    
        if (isEmpty()) {
    
    
            return false;
        }
        // rear 被设计在数组的末尾,所以是 -1
        rear = (rear - 1 + capacity) % capacity;
        return true;
    }

    /** Get the front item from the deque. */
    int getFront() {
    
    
        if (isEmpty()) {
    
    
            return -1;
        }
        return arr[front];
    }

    /** Get the last item from the deque. */
    int getRear() {
    
    
        if (isEmpty()) {
    
    
            return -1;
        }
        // 当 rear 为 0 时防止数组越界
        return arr[(rear - 1 + capacity) % capacity];
    }

    /** Checks whether the circular deque is empty or not. */
    bool isEmpty() {
    
    
        return front == rear;
    }

    /** Checks whether the circular deque is full or not. */
    bool isFull() {
    
    
        // 注意:这个设计是非常经典的做法
        return (rear + 1) % capacity == front;
    }
};

/**
 * Your MyCircularDeque object will be instantiated and called as such:
 * MyCircularDeque* obj = new MyCircularDeque(k);
 * bool param_1 = obj->insertFront(value);
 * bool param_2 = obj->insertLast(value);
 * bool param_3 = obj->deleteFront();
 * bool param_4 = obj->deleteLast();
 * int param_5 = obj->getFront();
 * int param_6 = obj->getRear();
 * bool param_7 = obj->isEmpty();
 * bool param_8 = obj->isFull();
 */

Supongo que te gusta

Origin blog.csdn.net/Gou_Hailong/article/details/128381718
Recomendado
Clasificación