Directorio de artículos
-
Introducción a la cola
-
Interfaces comunes para cola
-
Implementación de simulación de cola.
-
Introducción a la cola_prioritaria
-
Interfaces comunes de prioridad_queue
-
Implementación de simulación de prioridad_queue
-
adaptador de contenedor
-
Introducción a deque
-
Funtor
1. Introducción a la cola
- 1. Una cola es un adaptador de contenedor diseñado para operar en un contexto FIFO (primero en entrar, primero en salir), donde los elementos se insertan desde un extremo del contenedor y los elementos se extraen del otro extremo.
- 2. La cola se implementa como un adaptador de contenedor. El adaptador de contenedor encapsula una clase de contenedor específica como su clase de contenedor subyacente. La cola proporciona un conjunto específico de funciones miembro para acceder a sus elementos. Los elementos se colocan en la cola desde el final de la cola y se retiran de la cola desde el principio.
- 3. El contenedor subyacente puede ser una de las plantillas de clase de contenedor estándar u otras clases de contenedor especialmente diseñadas. El contenedor subyacente debe admitir al menos las siguientes operaciones:
- vacío: comprueba si la cola está vacía
- tamaño: devuelve el número de elementos válidos en la cola
- front: Devuelve una referencia al elemento principal de la cola
- back: Devuelve una referencia al último elemento de la cola
- push_back: cola al final de la cola
- pop_front: quitar la cola al principio de la cola
- 4. Las clases de contenedores estándar deque y list cumplen con estos requisitos. De forma predeterminada, si no se especifica ninguna clase de contenedor para la creación de instancias de cola, se utiliza la deque de contenedor estándar.
2. Interfaces comunes de cola.
Descripción de la interfaz de declaración de funcionesqueue() construye una cola vacíavacío () detecta si la cola está vacía y devuelve verdadero; de lo contrario, devuelve falsosize() devuelve el número de elementos válidos en la colafront() devuelve una referencia al elemento principal de la colaback() devuelve una referencia al último elemento de la colapush() coloca el elemento val en la cola al final de la colapop() quita de la cola el elemento principal de la colaswap() intercambia el contenido de dos contenedores
Demostración de interfaces relacionadas:
#include <iostream>
#include <queue>
int main()
{
std::queue<int> q;
q.push(1);
q.push(2);
q.push(3);
while (!q.empty()) {
std::cout << q.front() << " ";
q.pop();
}
return 0;
}
3. Implementación de simulación de cola.
#pragma once
namespace Queue
{
//这里默认是采用deque这种适配器来模拟栈
template<class T, class Contain = std::deque<T>>
class queue
{
public:
/*
queue()//这里不需要显示写构造函数,因为是自定义类型,直接调用默认构造函数就行
{}
*/
bool empty()
{
return _con.empty();
}
size_t size()const
{
return _con.size();
}
const T& front()const
{
return _con.front();
}
const T& back()const
{
return _con.back();
}
void push(const T& val)
{
_con.push_back(val);
}
void pop()
{
_con.pop_front();
}
void swap(queue<T, Contain>& q)
{
std::swap(_con, q._con);
}
private:
Contain _con;
};
}
4. Introducción a prioridad_queue
- 1. Una cola de prioridad es un adaptador de contenedor cuyo primer elemento es siempre el mayor de los elementos que contiene según estrictos criterios de ordenamiento débiles.
- 2. Este contexto es similar a un montón, donde los elementos se pueden insertar en cualquier momento y solo se puede recuperar el elemento del montón más grande (el elemento superior en la cola de prioridad).
- 3. La cola de prioridad se implementa como un adaptador de contenedor. El adaptador de contenedor encapsula una clase de contenedor específica como su clase de contenedor subyacente. La cola proporciona un conjunto específico de funciones miembro para acceder a sus elementos. Los elementos se extraen de la "cola" de un contenedor específico, que se denomina parte superior de la cola de prioridad.
- 4. El contenedor subyacente puede ser cualquier plantilla de clase de contenedor estándar o pueden ser otras clases de contenedor diseñadas específicamente. Se debe poder acceder al contenedor mediante iteradores de acceso aleatorio y admitir las siguientes operaciones:
- vacío (): comprueba si el contenedor está vacío
- size(): Devuelve el número de elementos válidos en el contenedor
- front(): Devuelve una referencia al primer elemento del contenedor
- push_back(): Insertar elementos al final del contenedor
- pop_back(): elimina el elemento al final del contenedor
- 5. Las clases de contenedores estándar vector y deque satisfacen estas necesidades. De forma predeterminada, se utiliza vector si no se especifica ninguna clase de contenedor para una instancia de clase de cola prioritaria particular.
- 6. Necesidad de admitir iteradores de acceso aleatorio para que la estructura del montón siempre se mantenga internamente. El adaptador de contenedor hace esto automáticamente llamando automáticamente a las funciones algorítmicas make_heap, push_heap y pop_heap cuando sea necesario.
5. Interfaces comunes de prioridad_queue
Descripción de la interfaz de declaración de funcionesPriority_queue()/priority_queue(first, last) construye una cola de prioridad vacíavacío () detecta si la cola de prioridad está vacía y devuelve verdadero; de lo contrario, devuelve falsotop() devuelve el elemento más grande (el elemento más pequeño) en la cola de prioridad, es decir, el elemento superior del montónpush(x) inserta el elemento x en la cola de prioridadpop () elimina el elemento más grande (más pequeño) en la cola de prioridad, es decir, el elemento superior del montón
1. De forma predeterminada, prioridad_queue es una pila grande
#include <iostream>
#include <deque>
#include <queue>
#include "queue.h"
#include <vector>
#include <functional>
#include <functional> // greater算法的头文件
void TestPriorityQueue()
{
// 默认情况下,创建的是大堆,其底层按照小于号比较
std::vector<int> v{3,2,7,6,0,4,1,9,8,5};
std::priority_queue<int> q1;
for (auto& e : v)
q1.push(e);
std::cout << q1.top() <<std:: endl;
// 如果要创建小堆,将第三个模板参数换成greater比较方式
std::priority_queue<int, std::vector<int>, std::greater<int>> q2(v.begin(), v.end());
std::cout << q2.top() << std::endl;
}
int main()
{
TestPriorityQueue();
return 0;
}
2. Si coloca datos de tipo personalizado en Priority_queue, el usuario debe proporcionar una sobrecarga de > o < en el tipo personalizado.
#include <iostream>
#include <deque>
#include <queue>
#include "queue.h"
#include <vector>
#include <functional>
#include <functional> // greater算法的头文件
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
bool operator<(const Date& d)const
{
return (_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day);
}
bool operator>(const Date& d)const
{
return (_year > d._year) ||
(_year == d._year && _month > d._month) ||
(_year == d._year && _month == d._month && _day > d._day);
}
friend std::ostream& operator<<(std::ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
void TestPriorityQueue()
{
// 大堆,需要用户在自定义类型中提供<的重载
std::priority_queue<Date> q1;
q1.push(Date(2018, 10, 29));
q1.push(Date(2018, 10, 28));
q1.push(Date(2018, 10, 30));
std::cout << q1.top() << std::endl;
// 如果要创建小堆,需要用户提供>的重载
std::priority_queue<Date, std::vector<Date>, std::greater<Date>> q2;
q2.push(Date(2018, 10, 29));
q2.push(Date(2018, 10, 28));
q2.push(Date(2018, 10, 30));
std::cout << q2.top() << std::endl;
}
int main()
{
TestPriorityQueue();
return 0;
}
6. Implementación de simulación de prioridad_queue
#pragma once
namespace Priority_queue
{
template<class T>
struct Less
{
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template<class T>
struct Greater
{
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
template<class T,class Container=std::vector<T>,class Compare=Less<T>>
class priority_queue
{
public:
priority_queue()
{}
template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
while (first != last) {
_con.push_back(*first);
first++;
int child = _con.size() - 1;
int parent = (child - 1) / 2;
for (int i = parent; i >= 0; i--) AdjustDown(i);
}
}
void AdjustUp(size_t child)
{
Compare com;
size_t parent = (child - 1) / 2;
while (child) {
if (com(_con[parent], _con[child])) {
std::swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else break;
}
}
void AdjustDown(size_t parent)
{
Compare com;
size_t child = parent * 2 + 1;
while (child < _con.size()) {
if (child + 1 < _con.size() && com(_con[child], _con[child + 1])) child++;
if (com(_con[parent], _con[child])) {
std::swap(_con[parent], _con[child]);
parent = (child - 1) / 2;
child = parent * 2 + 1;
}
else break;
}
}
void push(const T& val)
{
_con.push_back(val);
AdjustUp(_con.size() - 1);
}
void pop()
{
std::swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AdjustDown(0);
}
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
const T& top()
{
return _con[0];
}
private:
Container _con;
};
}
7. Adaptador de contenedor
1. El concepto de adaptador
2. La estructura subyacente de pila y cola en la biblioteca estándar STL
8. Introducción al deque
1. Introducción al principio de deque
2. Defectos de deque
En comparación con el vector, las ventajas de deque son :
- Al insertar y quitar el cabezal no es necesario mover elementos, lo cual es muy eficiente, y al expandirlo no es necesario mover una gran cantidad de elementos, por lo que su eficiencia debe ser alta.
- En comparación con la lista, la capa inferior es un espacio continuo, la utilización del espacio es relativamente alta y no es necesario almacenar campos adicionales.
Sin embargo, deque tiene un defecto fatal:
- No es adecuado para el recorrido, porque al atravesar, el iterador de deque necesita detectar con frecuencia si se mueve hasta el límite de un determinado espacio pequeño, lo que resulta en una baja eficiencia. En escenarios secuenciales, es posible que se requiera un recorrido frecuente, por lo que en la práctica, es necesario Cuando se trata de estructuras lineales, el vector y la lista tienen prioridad en la mayoría de los casos. No hay muchas aplicaciones de deque. Una aplicación que se puede ver hasta ahora es que STL lo usa como la estructura de datos subyacente de la pila y la cola. .
3. ¿Por qué elegir deque como contenedor predeterminado subyacente para la pila y la cola ?
La pila es una estructura de datos lineal especial con función de último en entrar, primero en salir. Por lo tanto, cualquier estructura lineal con operaciones push_back() y pop_back() se puede utilizar como contenedor subyacente de la pila, como vector y lista; la cola es una función especial primero en entrar, primero en salir. Las estructuras de datos lineales, siempre que tengan operaciones push_back y pop_front, se pueden utilizar como contenedor subyacente de la cola, como la lista. Sin embargo, deque se selecciona como contenedor subyacente de forma predeterminada para la pila y la cola en STL, principalmente porque:1. No es necesario atravesar la pila y la cola (por lo que la pila y la cola no tienen iteradores), solo necesitan operar en uno o ambos extremos fijos.2. Cuando los elementos en la cola crecen, deque es más eficiente que el vector (no es necesario mover una gran cantidad de datos al expandirse); cuando los elementos en la cola crecen, deque no solo es eficiente, sino que también tiene una alta uso de memoria. Combina las ventajas del deque y evita perfectamente sus deficiencias.
9. Funtor
1. El concepto de functor
Functor, también llamado objeto de función, es en realidad una estructura o clase que sobrecarga el operador (). Dado que el operador () está sobrecargado, usarlo es como llamar a una función, por lo que se denomina función "falsa".
2. Ejemplos de cómo escribir functores
template<class T>
struct Less
{
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template<class T>
struct Greater
{
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
3. Categorías de funtores
En el archivo de encabezado funcional de C++, se nos han proporcionado algunos functores que se pueden usar directamente.
1. Functor aritmético
1.plus calcula la suma de dos números
transformar(comienzo(a), final(a), comienzo(b), comienzo(a), más<int>());
2.menos resta dos números
transformar(comienzo(a), final(a), comienzo(b), comienzo(a), menos<int>());
3.multiplica dos números multiplicados entre sí
transformar(comienzo(a), final(a), comienzo(b), comienzo(a), multiplica<int>());
4.divides divide dos números
transformar(comienzo(a), final(a), comienzo(b), comienzo(a), divide<int>());
Operación del módulo de cinco módulos.
transformar(comienzo(a), final(a), comienzo(b), comienzo(a), módulo<int>());
6.negar el número opuesto
transformar(comenzar(a), finalizar(a), comenzar(a), negar<int>());
2. Funtor de relación
- 1.equal_to es igual
- 2.not_equal_to no es igual
- 3.mayor mayor que
- 4.menos menos que
- 5.greater_equal es mayor o igual a
- 6.less_equal es menor o igual a
3. Funtor lógico
- 1.lógico_y binario, busque &
- 2.lógico_o binario, buscar |
- 3.lógico_¡ni un yuan, por favor!