"In-depth practice C ++ template programming," Six - container standard library

1, the basic requirements of the container
a, not all data can be placed among the containers. Various containers stored template data type has a basic requirement - CopyConstructible. Process the data into a container of the copy constructor is through the process of creating a copy of the data of the data in the container.
b, the vessel must have some type of nested definitions relating to the type of the stored data.
The type of data storage vessel C :: value_type
C :: reference data reference type container
C :: read-only reference data type container const_reference
C :: size_type capacity of the container type, typically an unsigned integer type
C, in addition to nested type definitions, the container must also have a default constructor and a copy constructor.
d, the container should provide a series of nested definitions the iterator type and member functions.

 

 

e, Other:
Four new member function cbegin (), cend (), crbegin (), crend ​​() are clearly returns the corresponding read-only iterator.
The container must have member functions size (), max_size (), empty (), return the current number of elements in the container, whether the content may be a maximum number of elements and the container is empty.
The container must have a member function swap (C & a) is used interchangeable with another similar container contents.
It can be compared for equality between two similar containers.
There are other additional requirements.
 
2, the sequence type container
2.1、vector
a side vector is a container class template array. Successively stored in the vector data. It will apply in advance for a predicate vector memory space to save the data. As data continues to increase, when the reserved memory space is not enough, vector would then apply for a period of more space and moved to a new space in the existing data and then continue to accept new data. Since the continuous data stored in the memory space, the vector can provide a fast random access.
Therefore, Vector applied to the data as occasion demands but infrequent deletions efficient random access, and not require frequent deletions in the sequence where the data.
如果数据可以预估,可以先调用 reserve()函数申请足够空间,这样可以避免无谓的数据迁移。
 
void main()
{
    int array[] = { 1, 2, 3, 4, 5 };
    std::vector<int> v;

    v.reserve(5);
    v.assign(array, array + 5);

    typedef std::vector<int>::iterator iterator;
    iterator p = v.begin();
    iterator q = v.end() - 1;

    v.erase(p + 1, p + 3);

    v.insert(v.end(), array, array + 5);

    getchar();
}
由于erase以及insert操作,原本的p和q指针已经不指向原本预期的位置了。
vector除了要求所存数据类型是可复制构造的,还要求是可赋值的。
了解容器,就要了解支撑这个容器的底层的数据结构,才能以最高效的方式使用这个容器。
2.2、双向链表
2.3、双端序列
 
3、容器转换器
容器转换器是某种模板,这种模板利用某种容器而构建成某种数据结构。
容器转换器,是利 用容器实现特定数据结构的模板。标准中定义三种容器转换器模板:stack、queue、priority_queue。
stack与queue的模板有两个参数,前一参数定义stack及queue要保存的数据类型,后一参数则定义所用容器类型。
std::stack<int, std::vector<int>> vector_stack;    //用vector实现stack
    std::stack<int> deque_stack;    //用deque实现stack
    std::queue<char, std::list<char>> queue;        //用list实现queue
    std::queue<char> deque_queue;    //用deque实现queue
以priority_queue为例:
#include <iostream>
#include <queue>
#include <vector>

struct my_pair
{
    int first;
    int second;
};

struct comp_my_pair//这是一个函数对象
{
    bool operator()(my_pair const &left,
        my_pair const &right)
    {
        return left.first == right.first ? 
            left.second > right.second :
        left.first  > right.first;
    }
};

void main()
{
    my_pair array[] = {{3, 0}, {2, 1}, {1, 2}, {0, 3}, {0, 4}};
    using std::priority_queue;
    using std::vector;

    priority_queue<my_pair, vector<my_pair>, comp_my_pair> pq(array, array + 5);
    while(!pq.empty())
    {
        std::cout << pq.top().first << ", " << pq.top().second << std::endl;
        pq.pop();
    }

    return;
}
4、关联型容器
关联型容器的特征就是以“值”寻“址”,即容器可以快速找出某个给定值在容器中的位置,或者查无此值返回。
关联型容器包括集合set、多值集合multiset、映射map以及多值映射multimap。四种容器都 是以红黑树保存数据。所以这些容器的优势就等同于红黑树的优势。
a、要了解什么是红黑树,参考: https://blog.csdn.net/cout_sev/article/details/24628903
b、要知道什么是“多值”。
 
关联型容器都会支持一个函数型对象,用来比较插入的数据大小。
 
插入:执行插入操作时,如果你心中有一个map的底层数据结构模型,那么你就可以知道你每一步插入的时间复杂度是多少。并使用“智能插入”来实现高效插入。
举例:
typedef std::set<int> int_set;
typedef void func_type(int*, int*);

float measure(func_type func, int *start, int *end)
{
    //int start_clock = clock();
    func(start, end);
    //int end_clock = clock();
    return 0;
    //return float(end_clock - start_clock) / CLOCKS_PER_SEC;
}

void test_plain_insert(int *start, int *end)
{
    int_set s;
    s.insert(start, end);
    for(int_set::iterator it = s.begin(); it != s.end(); it++)
    {
        printf("%d ", *it);
    }
    printf("\n");
}

void test_smart_insert(int *start, int *end)
{
    int_set s;
    int_set::iterator prev = s.begin();
    for(; start != end; ++start)
    {
        prev = s.insert(prev, *start);
        for(int_set::iterator it = s.begin(); it != s.end(); it++)
        {
            printf("prev:%d ;", *prev);
            printf("%d ", *it);
        }
        printf("\n");

    }
    
    printf("\n");
}

void main()
{
    
    const int num = 8;
    const int half = num / 2;

    int array1[num];
    int array2[num];
    for(int i = 0; i < num; ++i)
    {
        array1[i] = i;
        array2[i] = (i & 1) ? (i - num) : (num - i);
    }

    measure(test_plain_insert, array2, array2 + num -1);
    measure(test_smart_insert, array2, array2 + num -1);
    //measure(test_plain_insert, array1, array1 + num -1);
    //measure(test_smart_insert, array1, array1 + num -1);
    return;
}

 

 

正常的插入insert(i, j)底层执行的是insert(end, v),而我们看这里的逻辑,end始终指向的是8;
而如果使用insert(prev, v),那么prev始终指向的是刚刚插入的位置;
就是二者的迭代器指向不同,导致了效率的差异。
所以,想用好stl库,一定要对其底层数据结构有深入了解。
 
 

 

Guess you like

Origin www.cnblogs.com/predator-wang/p/11518372.html