plantilla estándar

 

Programación tipo 1

 

õ Orientado a procesos -> Basado en objetos -> Orientado a objetos -> Genéricos

 

1. Haz que el programa sea lo más general posible

2. Abstraer el algoritmo de una estructura de datos específica y convertirlo en general

3. Las plantillas de C++ sientan una base clave para la programación genérica

4. STL es un ejemplo de programación genérica

 

 

2 Introducción a STL

¿Qué es STL?

 La biblioteca de plantillas estándar (Standard Tempate Library) es una de las partes más distintivas y prácticas de ANSI/ISO C++

Una breve historia de STL

Lo que el STL abstrae

Biblioteca de plantillas estándar (STL)

STL consta principalmente de seis partes principales:

※Iteradores (iteradores)

※Algoritmos

※ Contenedores

※ objetos de función (objetos de función)

※Asignadores de memoria (asignadores)

※adaptador

Los seis componentes principales de STL son todos conceptos abstractos.

 

3 contenedores

õConcepto de contenedor 

 Se utiliza para gestionar un conjunto de elementos.

 

Clases de contenedor de biblioteca estándar

ilustrar

contenedor de secuencia

vector (vector)

lista (lista)

deque (cola de dos extremos)

 

Rápida inserción y borrado desde atrás, acceso directo a cualquier elemento

Inserción y eliminación rápidas desde cualquier lugar, lista de doble enlace

Inserción y borrado rápido desde el anverso o el reverso, acceso directo a cualquier elemento

contenedor asociativo

conjunto (colección)

conjunto múltiple (conjunto múltiple)

mapa (mapa)

multimapa (mapeo múltiple)

 

Búsqueda rápida, no se permiten valores duplicados

Búsqueda rápida, que permite valores duplicados

Mapeo uno a uno, búsqueda rápida basada en palabras clave, no se permiten valores duplicados

Mapeo de uno a muchos, búsqueda rápida basada en palabras clave, que permite valores duplicados

adaptador de contenedor

pila (pila)

cola (cola)

prioridad_cola

 

último en entrar, primero en salir (LIFO)

primero en entrar, primero en salir (FIFO)

El elemento de mayor prioridad siempre se saca de la cola primero.

 

 

 

Clasificación de contenedores

õ Contenedores de secuencia

ô Cada elemento tiene una posición fija, según cuándo y dónde se inserte, independientemente del valor del elemento.

ô Contenedor secuencial, porque la posición de inserción del elemento no tiene nada que ver con el valor del elemento.

ô vector, deque, lista

õ Contenedores asociados

ô la posición del elemento depende de un criterio de clasificación específico, independientemente del orden de inserción

ô Los elementos del contenedor asociativo se ordenan, y cualquier elemento insertado determinará su posición de acuerdo con los criterios de ordenación correspondientes. Los contenedores asociativos se caracterizan por un muy buen rendimiento de búsqueda.

ô conjunto, multiconjunto, mapa, multimapa

Interfaz común para contenedores

õ Operador de contenedor genérico

ô ==,!=,>,>=,<,<=,=

õ método (función)

ô Método iterativo

ó comenzar(),finalizar(),rbegin(),rend()

ô Método de acceso

ó tamaño(),tamaño_máximo(),intercambiar(),vacío()

contenedor de secuencia

õ interfaz para contenedores de secuencias

ô Método de inserción

ó push_front(), push_back(), insert(), operador "="

ô Borrar método

desde pop(), borrar(), borrar()

ô método de acceso iterativo

ó usando iteradores

ô Otros métodos de acceso secuencial al contenedor (sin modificar los métodos de acceso)

ó operadores front(), back(), subíndice []

 

Contenedor de secuencia - Vector

Encabezado <vector>

    De hecho, es una matriz dinámica. El acceso aleatorio a cualquier elemento se puede hacer en tiempo constante. Agregar y eliminar elementos al final tiene un mejor rendimiento.

õ Agregar o quitar elementos del final de la matriz es muy rápido. Pero colocar elementos en el medio o en la cabeza lleva más tiempo.

õ vector es un contenedor secuencial, que se utiliza para acomodar secuencias lineales de longitud variable (es decir, grupos lineales), proporcionando un acceso aleatorio rápido a las secuencias (también conocido como acceso directo)

õ Un vector es una estructura dinámica que no tiene un tamaño fijo y puede aumentar o disminuir mientras se ejecuta el programa.

Ejemplo 1 vectores

 

#incluir <iostream>

#include <vector> //Este archivo de encabezado debe incluirse antes de usar el vector

 

utilizando el espacio de nombres estándar;

 

int principal()

{

     vector<int> coll; //contenedor de vectores para enteros

    

     // agregar elementos con valores de 1 a 6

     para(int i=1; i<=6; ++i) {

         coll.push_back(i);

     }

    

     //imprime todos los elementos seguidos de un espacio

     for(int i=0; i<coll.size(); ++i) {

         cout << coll[i] << ' ';

     }

     cout << endl;

}

 

Contenedor secuencial - cola de dos extremos

archivo de encabezado <deque>

    También es una matriz dinámica y el acceso aleatorio a cualquier elemento se puede completar en un tiempo constante (pero el rendimiento es inferior al del vector). Agregar y eliminar elementos en ambos extremos tiene un mejor rendimiento.

ô deque es una abreviatura de "cola de dos extremos".

ô Una cola de dos extremos es una cola con derechos de acceso relajados. Los elementos se pueden poner y quitar de la cola desde ambos extremos de la cola, y también se admite el acceso directo a través del operador de subíndice "[]".

ô Puede acceder a elementos aleatoriamente (acceso directo con índice).

ô Agregar o quitar elementos de la cabeza y la cola de la matriz es muy rápido. Pero colocar elementos en el medio o en la cabeza lleva más tiempo.

Ejemplo #2 deque

int principal()

{

     deque<flotador> coll; //contenedor deque para punto flotante

 

     //insertar elemento de 1.1 a 6.6 cada uno al frente

     para(int i=1; i<=6; ++i) {

         col.push_front(i*1.1); //insertar al frente

     }

 

     //imprime todos los elementos seguidos de un espacio

     for(int i=0; i<coll.size(); ++i) {

         cout << coll[i] << ' ';

     }

     cout << endl;

}

 

Contenedor secuencial - lista

archivo de encabezado de lista <lista>

õ Lista doblemente enlazada, la adición y eliminación de elementos en cualquier posición se puede completar en tiempo constante. No se admite el acceso aleatorio.

ô La lista se utiliza principalmente para almacenar la lista doblemente enlazada, que se puede recorrer desde cualquier extremo. Las listas también proporcionan operaciones de empalme, que insertan elementos de una secuencia en otra.

ô No proporciona acceso aleatorio (ir a los elementos a acceder en orden, O(n)).

ô Realice la inserción o el borrado en cualquier posición muy rápidamente, simplemente ajuste el puntero internamente.

Ejemplo 3 lista enlazada

int principal()

{

     lista<carácter> coll; //contenedor de lista para charactor

 

     //añadir elementos de 'a' a 'z'

     for(char c='a'; c<='z'; ++c) {

         col.push_back(c);

     }

 

     while(!coll.empty()) {

         cout << coll.front() << ' ';

         col.pop_front();

     }

     cout << endl;

}

contenedor asociativo

õ  Conjuntos/Multiconjuntos

encabezado <conjunto>

   conjunto significa colección. No se permiten los mismos elementos en el conjunto, pero sí se permiten los mismos elementos en el conjunto múltiple.

ôLos elementos internos  se clasifican automáticamente según sus valores

ô  Los elementos con el mismo valor en Conjunto solo pueden aparecer una vez, y los Conjuntos múltiples pueden contener varios elementos con el mismo valor.

ôEstá  implementado internamente por un árbol binario, que es fácil de encontrar.

Ejemplo 4

int principal()

{

     //tipo de la colección

     typedef std::set<int> IntSet;

 

     IntSet coll; //establecer contenedor para valores int

     coll.insertar(1);

     coll.insertar(6);

     coll.insertar(2);

     IntSet::const_iterator pos;

 

     for(pos = coll.begin(); pos!= coll.end(); ++pos) {

         estándar::cout <<*pos <<' ';

     }

     estándar::cout << estándar::endl;

}

 

õ  Mapas/Multimapas

   Encabezado <mapa>

   La diferencia entre mapa y conjunto es que el mapa almacena pares de clave/valor.

   Y ordene los elementos según la clave, y recupere rápidamente los elementos según la clave

   La diferencia entre mapa y mapa múltiple es si se permite que varios elementos tengan el mismo valor clave.

ô  Los elementos del Mapa son pares clave-valor/valor real, y los elementos internos se ordenan automáticamente según sus valores.

ô  Los elementos con el mismo valor en el Mapa solo pueden aparecer una vez, y los Multimapas pueden contener múltiples elementos con el mismo valor.

ôEstá  implementado internamente por un árbol binario, que es fácil de encontrar.

ejemplo 5

#incluir <iostream>

#incluir <mapa>

#incluir <cadena>

utilizando el espacio de nombres estándar;

int principal()

{

     //tipo de la colección

     typedef multimapa<int, cadena> IntStringMMap;

 

     IntStringMMap coll; // contenedor para int/string

     // aviso make_pair devuelve un objeto de par para la función de conveniencia

     coll.insert(hacer_par(6, "cadena"));

     coll.insert(make_pair(1, "es"));

     coll.insert(make_pair(3, "multimapa"));

 

     IntStringMMap::iterador pos;

     for(pos = coll.begin(); pos!=coll.end; ++pos) {

         cout << pos->segundo << ' ';

     }

 

     cout << endl;

}

Introducción a los adaptadores de contenedores

1) pila: archivo de encabezado <pila>

     pila. es una secuencia finita de elementos, de modo que los elementos que se eliminan, recuperan y modifican en la secuencia solo pueden ser aquellos que se insertaron más recientemente en la secuencia. Principio de último en entrar, primero en salir

2) cola: archivo de encabezado <cola>

   cola. La inserción solo es posible en la cola, y la eliminación, recuperación y modificación solo se permiten en la cabeza. Según el principio de primero en entrar, primero en salir.

3) prioridad_cola: archivo de encabezado <cola>

     cola de prioridad. El elemento de mayor prioridad siempre se saca de la cola primero.

funciones miembro públicas del contenedor

1) Funciones de miembro comunes a todos los contenedores de biblioteca estándar:

ô es equivalente a los operadores que comparan lexicográficamente los tamaños de dos contenedores:  
 =, < , <= , > , >=, == , !=

ô vacío: determina si hay un elemento en el contenedor

ô max_size: el número máximo de elementos que se pueden colocar en el contenedor

ô tamaño: el número de elementos en el contenedor

ô swap: intercambiar el contenido de dos contenedores

 

2) Funciones solo en contenedores de primera clase:

         begin devuelve un iterador que apunta al primer elemento en el contenedor

         end devuelve un iterador que apunta a la posición después del último elemento en el contenedor

         rbegin devuelve un iterador que apunta al último elemento del contenedor

         rend devuelve un iterador que apunta a la posición que precede al primer elemento en el contenedor

         borrar elimina uno o más elementos del contenedor

         borrar elimina todos los elementos del contenedor

Capacidades comunes para contenedores

õ Todos los contenedores proporcionan semántica de valor, no semántica de referencia. Cuando el contenedor realiza la operación de insertar elementos, internamente implementa una operación de copia. Por lo tanto, los elementos almacenados en el contenedor STL deben poder copiarse (se debe proporcionar el constructor de copias).

õ Cada contenedor proporciona una función que devuelve un iterador, y el iterador devuelto se puede utilizar para acceder a los elementos.

õ Usualmente el STL no arroja excepciones. Requiere el uso de un par de corredores para garantizar que se pasen los parámetros correctos.

Interoperabilidad de contenedores

õ inicialización: cada contenedor proporciona un constructor predeterminado, un constructor de copia

lista<int> l;

...

vector<int> ivec( l.begin(), l.end() ); //Inicialización completa con la aridad de un determinado contenedor como valor inicial

matriz int[] = {1, 2, 3, 4};

...

// Complete la inicialización con los elementos de una matriz como valor inicial

set<int> iset(matriz, matriz+tamaño(matriz)/tamaño(matriz[0]));

 

õ funciones de operación dependientes del tamaño

c.size() //devuelve el número de elementos en el contenedor

c.empty() //Juzga si el contenedor está vacío (equivalente a size()==0, pero puede ser más rápido)

c.max_size() // devuelve el máximo número posible de elementos

õ función que devuelve un iterador

c.begin() //devuelve un iterador que apunta al primer elemento

c.end() //devuelve un iterador que apunta al último elemento

c.rbegin() //Devuelve un iterador inverso, apuntando al primer elemento en la visita de retorno inverso

c.rend() //Devuelve un iterador inverso, apuntando a la siguiente posición del último elemento durante el acceso inverso

õ operación de comparación

c1 == c2 //Juzga si c1 es igual a c2

c1 != c2 //juzgar si c1 no es igual a c2 es equivalente a!(c1 == c2)

c1 < c2 //Juzga si c1 es menor que c2

c1 > c2 //juzgar si c1 es mayor que c2 es equivalente a (c1 <= c2)

c1 <= c2 // juzgar si c1 es menor o igual que c2 es equivalente a (c2 < c1)

c1 >= c2 //Juzga si c1 es mayor o igual que c2, equivalente a!(c1 < c2)

c1 = c2 //Asignar todos los elementos de c2 a c1

4 Breve descripción del Iterador

õ Iteradores y Contenedores

ô A través de iteradores, podemos acceder y atravesar contenedores de la misma manera (es decir, la abstracción de genéricos).

 

El concepto de iteradores

Los iteradores son la versión orientada a objetos de los punteros.

ô Un puntero puede apuntar a una dirección en la memoria

ô Un iterador puede apuntar a una posición en el contenedor

õ Cada plantilla de clase de contenedor de STL define un conjunto de clases iteradoras correspondientes. Usando un iterador, una función de algoritmo puede acceder a un elemento en una posición específica en un contenedor sin preocuparse por el tipo específico del elemento.

ô Un iterador es un objeto que puede atravesar todos o parte de los elementos en el contenedor STL.

ô Un iterador apunta a una posición específica en el contenedor.

ô Habilidad para atravesar estructuras de datos complejas.

õ Operaciones básicas de iteradores

El uso es el mismo que el puntero, de hecho, el puntero es una especie de iterador

õ tipo de iterador

ô iterador de entrada

õ se puede usar para leer datos de una secuencia

ô iterador de salida

õ Permite escribir datos a la secuencia

ô iterador hacia adelante

õ es tanto un iterador de entrada como un iterador de salida, y puede atravesar la secuencia en una dirección

ô iterador bidireccional

õ es similar a un iterador directo, pero atraviesa los datos en ambas direcciones

iterador de acceso aleatorio

õ también es un iterador bidireccional, pero puede saltar entre dos posiciones cualesquiera de la secuencia.

 

 

Tipos de iteradores de biblioteca estándar

ilustrar

Ingrese InputIterator

Leer elementos del contenedor. El iterador de entrada solo puede avanzar (es decir, desde el principio del contenedor hasta el final del contenedor) un elemento a la vez.

Para releer hay que empezar desde el principio.

Salida OutputIterator

Escribe elementos en el contenedor.

El iterador de salida solo se puede mover hacia adelante un elemento a la vez.

Los iteradores de salida que se reescribirán deben comenzar desde cero

reenviar Reenviar iterador

 

Funciones que combinan iteradores de entrada e iteradores de salida,

y conserva su posición en el contenedor (como información de estado),

Así que releer y escribir no tiene que empezar desde cero.

Iterador bidireccional bidireccional

Combinando la función de iterador hacia adelante con la función de movimiento hacia atrás

(es decir, desde el final de la secuencia del contenedor hasta el comienzo de la secuencia del contenedor)

随机访问 RandomAccseeIterator

组合双向迭代器的功能,并能直接访问容器中的任意元素,即可向前或向后调任意个元素。

 

不同迭代器所能进行的操作(功能)

õ  所有迭代器: ++p, p ++

õ  输入迭代器: * p, p = p1, p == p1 , p!= p1

õ  输出迭代器: * p, p = p1

õ  正向迭代器: 上面全部

õ  双向迭代器: 上面全部,--p, p --,

õ  随机访问迭代器: 上面全部,以及:

ô  p+= i, p -= i,

ô  p + i: 返回指向 p 后面的第i个元素的迭代器

ô  p - i: 返回指向 p 前面的第i个元素的迭代器

ô  p[i]: p 后面的第i个元素的引用

ô  p < p1, p <= p1, p > p1, p>= p1

õ  迭代器示例

例6

int main()

{

     list<char> coll;  // list container for character elements

     //append elements from 'a' to 'z'

     for(char c='a'; c<='z'; ++c) {

         coll.push_back(c);

     }

 

     list<char>::const_iterator pos;

     for(pos = coll.begin(); pos != coll.end(); ++pos) {

         cout << *pos <<' ';

     }

     cout << endl;

}

 

5   算法(algorithm)

õ  STL中提供能在各种容器中通用的算法,比如插入,删除,查找,排序等。大约有70种标准算法。

õ          算法就是一个个函数模板。

õ  算法表现为一系列的函数模板,它们完整定义在STL头文件中。一般这些函数模板都使用迭代器作为它的参数和返回值,因此泛型算法不依赖于具体的容器。

õ  STL中也定义了一些标准的函数对象,如果以功能划分,可以分为算术运算、关系运算、逻辑运算三大类。为了调用这些标准函数对象,需要包含头文件<functional>。

õ  泛型算法分类为

õ  (1)不修改序列的操作

õ     find( )、cout( )、equal( )、mismatch( )和search( )等。

õ  (2)修改序列的操作

õ      swap( )、copy( )、transform( )、replace( )、remove( )、

õ       reverse( )、rotate( )和fill( )等。

õ  (3)排序、合并和相关的操作

õ      sort( )、binary_search( )、merge( )、min( )和max( )等。

每个泛型算法(generic algorithm)的实现都独立于单独的容器类型,它消除了算法的类型依赖性

算法示例:find()

template<class InIt, class T>

InIt find(InIt first, InIt last, const T& val);

õ  first 和 last 这两个参数都是容器的迭代器,它们给出了容器中的查找区间起点和终点。

ô  这个区间是个左闭右开的区间,即区间的起点是位于查找范围之中的,而终点不是

õ  val参数是要查找的元素的值

õ  函数返回值是一个迭代器。如果找到,则该迭代器指向被找到的元素。如果找不到,则该迭代器指向查找区间终点。

例7

#include <vector>

#include <algorithm>

#include <iostream>

 

using namespace std;

void main()

{

     int array[10] = {10, 20, 30, 40};

     vector<int> v;

     v.push_back(1);

     v.push_back(2);

     v.push_back(3);

     v.push_back(4);

 

     vector<int>::iterator p;

     p=find(v.begin(), v.end(), 3);

     if(p != v.end()) {

         cout<< *p <<endl;

     }

 

     p=find(v.begin(), v.end(), 9);

     if(p == v.end()) {

         cout << "not find" << endl;

     }

 

     p=find(v.begin()+1, v.end()-2, 1);

     if(p != v.end()) {

         cout<< *p << endl;

     }

 

     int *pp=find(array, array+4, 20);

     cout << *pp << endl;

}

 

函数对象

õ  在C++中,为了使程序的安全性更好,采用“引用”来代替指针作为函数的参数或返回值。在C++的泛型算法中类似地采用了“函数对象”(function object)来代替函数指针。函数对象是一个类,它重载了函数调用操作符(operator())。该操作符封装了应该被实现为一个函数的操作。典型情况下,函数对象被作为实参传递给泛型算法。和“引用”一样,“函数对象”独立使用比较少。函数对象亦称拟函数对象(function_like object)和函子(functor)。下面给出一个求和函数对象的定义:

template<typename T>class Sum

{

     T res;

public:

     sum(T i=0):res(i)

     {

    

     }//构造函数,即sum(T i=0){res=i;}

     void operator()(T x)

     {

         res+=x;-

     }//累加

     T result() const

     {

         return res;

     }//

}

õ  对象与函数指针相比较有三个优点:第一,函数指针是间接引用,不能作为内联函数,而函数对象可以,这样速度更快;第二,函数对象可以拥有任意数量的额外数据,用这些数据可以缓冲当前数据和结果,当然多数情况下不一定使用,上例中res就是一个额外数据;第三,编译时对函数对象做类型检查。

泛型算法

õ  在C++标准库中给出了70余种算法,泛型算法函数名都加有后缀,这些后缀的意思如下:

õ  _if   表示函数采用的操作是在元素上,而不是对元素的值本身进行操作。如find_if算法表示查找一些值满足函数指定条件的元素,而find查找特定的值。

õ  _copy         表示算法不仅操作元素的值,而且还把修改的值复制到一个目标范围中。reverser算法颠倒范围中元素的排列顺序,而reverse_copy算法同时把结果复制到目标范围中。

õ  其它的后缀从英文意思上立即可以认出其意义

 

  其次我们介绍泛型算法的构造与使用方法。所有泛型算法的前两个实参是一对iterator,通常称为first和last,它们标出要操作的容器或内置数组中的元素范围。元素的范围,包括first,但不包含last的左闭合区间。即:

[first,last)

当first==last成立,则范围为空。

对iterator的类则要求在每个算法声明中指出(5个基本类别),所声明的是最低要求。

 

泛型算法分以下几类:

  1. 查找算法:有13种查找算法用各种策略去判断容器中是否存在一个指定值。equal_range()、lower_bound()和upper_bound()提供对半查找形式。
  2. 排序和通用整序算法:共有14种排序(sorting)和通用整序(ordering)算法,为容器中元素的排序提供各种处理方法。所谓整序,是按一定规律分类,如分割(partition)算法把容器分为两组,一组由满足某条件的元素组成,另一组由不满足某条件的元素组成。
  3. 删除和代替算法:有15种删除和代替算法。
  4. 排列组合算法:有2种算法。排列组合是指全排列。如:三个字符{a,b,c}组成的序列有6种可能的全排列:abc,acb,bac,bca,cab,cba;并且六种全排列按以上顺序排列,认为abc最小,cba最大,因为abc是全顺序(从小到大)而cba是全逆序(从大到小)。
  5. 生成和改变算法:有6种,包含生成(generate),填充(fill)等等。
  6. 关系算法:有7种关系算法,为比较两个容器提供了各种策略,包括相等(equal()),最大(max()),最小(min())等等。 
  7. 集合算法:4种集合(set)算法提供了对任何容器类型的通用集合操作。包括并(union),交(intersection),差(difference)和对称差(symmetric difference)。

小结

Ø   模板是C++类型参数化的多态工具。

        C++提供函数模板和类模板

Ø   模板定义以模板说明开始。

        类属参数必须在模板定义中至少出现一次

Ø   同一个类属参数可以用于多个模板

Ø   类属参数可用于函数的参数类型、返回类型和声明函数中的变量

Ø   模板由编译器根据实际数据类型实例化,生成可执行代码。实例化的函数模板称     为模板函数;实例化的类模板称为模板类

Ø   函数模板可以用多种方式重载

Ø   类模板可以在类层次中使用

 

Supongo que te gusta

Origin blog.csdn.net/besidemyself/article/details/7296311
Recomendado
Clasificación