1-STL体系结构基础介绍

一、STL 六大部件(Components)

  • 容器(Containers)
  • 分配器(Allocators)
  • 算法(Algorithms)
  • 迭代器(Iterators)
  • 适配器(Adapters)
  • 仿函数(Functors)

六大部件的关系目前可以初步用下图来表示:
在这里插入图片描述
下面我们用一个程序来使用这六大部件
t
1. 前闭后开区间

  对于迭代器来说,begin() 指向的是容器的第一个元素,end() 指向容器最后一个元素的下一个位置,所以经常使用 end() 来判断是否遍历到了容器结尾。如下图所示:
在这里插入图片描述

Container<T> c;
...
Container<T>::iterator it = c.begin();
for(; it != c.end(); ++it)
	...

2. range-based for statement (since C++11)

【语法】
for(decl : coll)
{
	statement;
}
【举例】
vector<int> vec;
...
for(auto elem : vec)
{
	cout << elem << endl;  // 打印vec中每一个元素
}
for(auto &elem : vec)
{
	elem *= 3;
}

3. auto 关键字(since C++11)

list<string> c;
...
list<string>::iterator it;
it = find(c.begin(), c.end(), target);

【等同于】
list<string> c;
...
auto it = find(c.begin(), c.end(), target);

二、容器之分类

  其实容器主要分为两大类:序列容器和关联容器。但是 C++11 后新增了 Unordered Containers,其实它的本质还是属于关联容器。

1. 序列容器(Sequence Containers)

  所谓序列式容器,其中的元素都可序,但未必有序,C++ 语言本来提供了一种序列式容器 array,STL 另外再提供 vector,list,deque,stack,queue,priority-queue 等等序列式容器。其中 stack 和 queue 由于只是将 deque 改头换面,技术上被归类为一种配接器(Adapter)。

1. Array(数组)(C++11)

  在 C/C++ 里面本来就存在数组,它是语言的一部分。在 C++11 中把数组也变成一个 class。Array在内存中是连续分配的, 当初你定义了多大空间它就有多大空间,它是一个定长数组,当数组中空间不够时,它是没有办法扩充的。
在这里插入图片描述

2. Vector

单向开口的动态数组,在内存中是连续分配的。当 vector 中空间不够时,它会自动扩充(分配器)。
在这里插入图片描述

3. Deque

双向开口的的队列,简称双端队列。deque 是由分段的连续线性空间组合而成
在这里插入图片描述

4. List

双向环状链表,在内存中不一定是连续存储的。
在这里插入图片描述

5. Forward-List(C++11)

单向链表,
在这里插入图片描述

2. 关联容器(Associative Containers)

  标准的 STL 关联式容器分为 set(集合)和 map(映射)两大类,以及这两大类的衍生体 mutiset(多键集合)和 multimap(多键映射表)。这些容器的底层均以 RB-tree(红黑树)完成。RB-tree 也是一个独立容器,但并不开放给外界使用。

此外,SGI STL 还提供了一个不再标准规格之列的关联式容器:hash table(散列表),以及以此 hash table 为底层实现机制而完成的 hash_set(散列集合)、hash_map(散列映射表)、hash_multiset(散列多键集合)和 hash_multimap(散列多键映射表)。

该容器下元素由 key 和 value 组成。key 为关键值,通过 key 可以很快找到 value 的值。所以关联容器很适合做快速的查找。

1. Set/Multiset

set 的 key 就是 value。set 中的元素不允许重复,如果想要重复,使用 multiset。
在这里插入图片描述

2. Map/Multimap

map 由 key 和 value 组成。map 中的元素的键值不允许重复,如果想要重复,使用 multimap。
在这里插入图片描述

3. 不定序容器(Unordered Containers)(C++11)

其实 Unordered Containers 也是一种关联式容器。底层是使用 hashtable 实现。

目前,hashTable 大多都采用很多链表组成。HashTable Separate Chaining 数据结构如下图所示:
在这里插入图片描述

1. Unordered Set/Multiset
在这里插入图片描述

2. Unordered Map/Multimap
在这里插入图片描述

三、容器测试

1. 使用容器 array

#include <iostream>
#include <array>
#include <ctime>
#include <cstdlib>
using namespace std;
#define ASIZE 500000
// 随机生成 1-500000 之间的数
long get_a_target_long()
{
    return rand() % 500000 + 1;
}
int compareLongs(const void *p1, const void *p2)
{
    return *(long *)p1 < *(long *)p2;
}

void test_array()
{
    cout << "\ntest array() ..............\n";
    array<long, ASIZE> arr;

    clock_t startTime = clock();
    for(long i = 0; i < ASIZE; i++)
        arr[i] = rand() % 500000 + 1;
    cout << "milli-seconds:" << (clock() - startTime) << endl;
    cout << "array.size():" << arr.size() << endl;
    cout << "array.front():" << arr.front() << endl;
    cout << "array.back():" << arr.back() << endl;
    cout << "array.data():" << arr.data() << endl;

    int target = get_a_target_long();

    startTime = clock();

    // 排序
    // void qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const void*));
    qsort(arr.data(), ASIZE, sizeof(long), compareLongs);

    // 二分查找:使用二分查找之前一定要先排序
    // void* bsearch (const void* key, const void* base, size_t num, size_t size, int (*compar)(const void*,const void*));
    long *pItem = (long *)bsearch(&target, (arr.data()), ASIZE, sizeof(long), compareLongs);
    cout << "qsort() + bsearch(), milli-seconds:" << (clock() - startTime) << endl;
    if(pItem)
        cout << "found:" << *pItem << endl;
    else
        cout << "Not Found!" << endl;

}

int main()
{
    test_array();
    return 0;
}

在这里插入图片描述

2. 使用容器 vector

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <ctime>
#include <cstdlib>
using namespace std;
// ****************** vector ********************//
string get_a_target_string()
{
    srand(time(nullptr));
    long target = rand() % 50000 + 1;
    char buf[10];
    snprintf(buf, 10, "%d", target);
    return string(buf);
}
int compareString(const void *str1, const void *str2)
{
    return *(string *)str1 < *(string *)str2;
}
void test_vector(long &value)
{
    cout << "\ntest_vector()...................... \n";

    vector<string> str;
    char buf[10];

    clock_t startTime = clock();
    for(long i = 0; i < value; i++)
    {
        try{ // 当内存不够时,捕获异常
            snprintf(buf, 10, "%d", rand());
            str.push_back(string(buf));
        }
        catch(exception &p){
            cout << "i = " << i << " " << p.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds:" << (clock() - startTime) << endl;
    cout << "vector.size():" << str.size() << endl;
    cout << "vector.front():" << str.front() << endl;
    cout << "vector.back():" << str.back() << endl;
    cout << "vector.data():" << str.data() << endl;
    cout << "vector.capacity():" << str.capacity() << endl; // 一定比 size 大

    string target = get_a_target_string();

    startTime = clock();

    auto pItem = find(str.begin(), str.end(), target); // find 返回迭代器
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;

    if(pItem != str.end())
        cout << "find:" << *pItem << endl;
    else
        cout << "Not found" << endl;
}
// ****************** vector ********************//
int main()
{
    long target = 1000000;
    test_vector(target);
    return 0;
}

在这里插入图片描述

3. 使用容器 list

#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
#include <ctime>
#include <cstdlib>
using namespace std;
// ****************** list ********************//
void test_list(long &value)
{
    cout << "\ntest_list()...................... \n";

    list<string> str;
    char buf[10];

    clock_t startTime = clock();
    for(long i = 0; i < value; i++)
    {
        try{ // 当内存不够时,捕获异常
            snprintf(buf, 10, "%d", rand());
            str.push_back(string(buf));
        }
        catch(exception &p){
            cout << "i = " << i << " " << p.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds:" << (clock() - startTime) << endl;
    cout << "list.size():" << str.size() << endl;
    cout << "list.max_size():" << str.max_size() << endl;
    cout << "list.front():" << str.front() << endl;
    cout << "list.back():" << str.back() << endl;

    string target = get_a_target_string();

    startTime = clock();

    auto pItem = find(str.begin(), str.end(), target);
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;

    if(pItem != str.end())
        cout << "find:" << *pItem << endl;
    else
        cout << "Not found" << endl;

    startTime = clock();
    str.sort(); // 调用容器内部的 sort 方法,不是标准库中的 sort。
    cout << "str.sort(), mill-seconds:" << (clock() - startTime) << endl;
}
// ****************** list ********************//
int main()
{
    long target = 1000000;
    test_list(target);
    return 0;
}

在这里插入图片描述

4. 使用容器 forward_list

#include <iostream>
#include <vector>
#include <list>
#include <forward_list>
#include <algorithm>
#include <functional>
#include <ctime>
#include <cstdlib>
using namespace std;
// ****************** forward_list ********************//
void test_forward_list(long &value)
{

    cout << "\ntest_forward_list()...................... \n";

    forward_list<string> str;
    char buf[10];

    clock_t startTime = clock();
    for(long i = 0; i < value; i++)
    {
        try{ // 当内存不够时,捕获异常
            snprintf(buf, 10, "%d", rand());
            str.push_front(string(buf)); // 只有 push_front() 方法,没有 push_back() 方法
        }
        catch(exception &p){
            cout << "i = " << i << " " << p.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds:" << (clock() - startTime) << endl;
    cout << "forward_list.max_size():" << str.max_size() << endl;
    cout << "forward_list.front():" << str.front() << endl;
    //cout << "forward_list.back():" << str.back() << endl;   // 没有此函数
    //cout << "forward_list.size():" << str.size() << endl; // 没有此函数

    string target = get_a_target_string();

    startTime = clock();

    auto pItem = find(str.begin(), str.end(), target);
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;

    if(pItem != str.end())
        cout << "find:" << *pItem << endl;
    else
        cout << "Not found" << endl;

    startTime = clock();
    str.sort();
    cout << "str.sort(), mill-seconds:" << (clock() - startTime) << endl;
}
// ****************** forward_list ********************//

int main()
{
    long target = 1000000;
    test_forward_list(target);
    return 0;
}

在这里插入图片描述

注意:只有 list 和 forward_list 才有自带的排序方法。

5. 使用容器 deque

deque 是由分段的连续线性空间组合而成。
在这里插入图片描述

#include <iostream>
#include <vector>
#include <list>
#include <forward_list>
#include <deque>
#include <algorithm>
#include <functional>
#include <ctime>
#include <cstdlib>
using namespace std;
// ****************** deque ********************//
void test_deque(long &value)
{

    cout << "\ntest_forward_list()...................... \n";

    deque<string> str;
    char buf[10];

    clock_t startTime = clock();
    for(long i = 0; i < value; i++)
    {
        try{ // 当内存不够时,捕获异常
            snprintf(buf, 10, "%d", rand());
            str.push_front(string(buf));
        }
        catch(exception &p){
            cout << "i = " << i << " " << p.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds:" << (clock() - startTime) << endl;
    cout << "deque.size():" << str.size() << endl;
    cout << "deque.front():" << str.front() << endl;
    cout << "deque.back():" << str.back() << endl;
    cout << "deque.max_size():" << str.max_size() << endl;

    string target = get_a_target_string();

    startTime = clock();

    auto pItem = find(str.begin(), str.end(), target);
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;

    if(pItem != str.end())
        cout << "find:" << *pItem << endl;
    else
        cout << "Not found" << endl;

    startTime = clock();
    sort(str.begin(), str.end());
    cout << "sort(), mill-seconds:" << (clock() - startTime) << endl;
}
// ****************** deque ********************//

int main()
{
    long target = 1000000;
    test_deque(target);
    return 0;
}

在这里插入图片描述

6. 使用容器 multiset

#include <list>
#include <forward_list>
#include <deque>
#include <algorithm>
#include <functional>
#include <ctime>
#include <cstdlib>
#include <set>
#include <map>
using namespace std;
// ****************** multiset ********************//
void test_multiset(long &value)
{

    cout << "\ntest_multiset()...................... \n";

    multiset<string> str;
    char buf[10];

    clock_t startTime = clock();
    for(long i = 0; i < value; i++)
    {
        try{ // 当内存不够时,捕获异常
            snprintf(buf, 10, "%d", rand());
            str.insert(string(buf));
        }
        catch(exception &p){
            cout << "i = " << i << " " << p.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds:" << (clock() - startTime) << endl;
    cout << "multise.size():" << str.size() << endl;
    cout << "multise.max_size():" << str.max_size() << endl;

    string target = get_a_target_string();

    startTime = clock();

    auto pItem = find(str.begin(), str.end(), target); // 采用算法中的 find
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;

    if(pItem != str.end())
        cout << "find:" << *pItem << endl;
    else
        cout << "Not found" << endl;

    startTime = clock();
    auto it = str.find(target);  // 调用容器自身的 find
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;
    if(it != str.end())
        cout << "find:" << *it << endl;
    else
        cout << "Not found" << endl;
}
// ****************** multiset ********************//

int main()
{
    long target = 1000000;
    test_multiset(target);
    return 0;
}

在这里插入图片描述

7. 使用容器 multimap

#include <list>
#include <forward_list>
#include <deque>
#include <algorithm>
#include <functional>
#include <ctime>
#include <cstdlib>
#include <set>
#include <map>
using namespace std;
// ****************** multimap ********************//
void test_multimap(long &value)
{

    cout << "\ntest_multimap()...................... \n";

    multimap<long, string> str;
    char buf[10];

    clock_t startTime = clock();
    for(long i = 0; i < value; i++)
    {
        try{ // 当内存不够时,捕获异常
            snprintf(buf, 10, "%d", rand());
            // multimap 不可使用 [] 做 insertion
            str.insert(pair<long, string>(i, buf)); 
            //str.insert({i, buf}); // 第二种插入方式
        }
        catch(exception &p){
            cout << "i = " << i << " " << p.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds:" << (clock() - startTime) << endl;
    cout << "multimap.size():" << str.size() << endl;
    cout << "multimap.max_size():" << str.max_size() << endl;

    long target = get_a_target_long();

    startTime = clock();
    auto it = str.find(target);
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;
    if(it != str.end())
        cout << "find, value:" << it->second << endl;
    else
        cout << "Not found" << endl;
}
// ****************** multimap ********************//

int main()
{
    long target = 1000000;
    test_multimap(target);
    return 0;
}

在这里插入图片描述

8. 使用容器 unordered_multiset

// ****************** unordered_multiset ********************//
void test_unordered_multiset(long &value)
{

    cout << "\ntest_unordered_multiset()...................... \n";

    unordered_multiset<string> str;
    char buf[10];

    clock_t startTime = clock();
    for(long i = 0; i < value; i++)
    {
        try{ // 当内存不够时,捕获异常
            snprintf(buf, 10, "%d", rand());
            str.insert(string(buf)); // 只有 push_front() 方法,没有 push_back() 方法
        }
        catch(exception &p){
            cout << "i = " << i << " " << p.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds:" << (clock() - startTime) << endl;
    cout << "unordered_multiset.size():" << str.size() << endl;
    cout << "unordered_multiset.max_size():" << str.max_size() << endl;
    cout << "unordered_multiset.bucket_count():" << str.bucket_count() << endl; // 篮子的个数
    cout << "unordered_multiset.load_factor():" << str.load_factor() << endl;
    cout << "unordered_multiset.max_load_factor():" << str.max_load_factor() << endl;
    cout << "unordered_multiset.max_bucket_count():" << str.max_bucket_count() << endl;

    string target = get_a_target_string();

    startTime = clock();

    auto pItem = find(str.begin(), str.end(), target);
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;

    if(pItem != str.end())
        cout << "find:" << *pItem << endl;
    else
        cout << "Not found" << endl;

    startTime = clock();
    auto it = str.find(target);
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;
    if(it != str.end())
        cout << "find:" << *it << endl;
    else
        cout << "Not found" << endl;
}
// ****************** unordered_multiset ********************//

int main()
{
    long target = 1000000;
    test_unordered_multiset(target);
    return 0;
}

在这里插入图片描述
在这里插入图片描述

9. 使用容器 unordered_multimap

// ****************** unordered_multimap ********************//
void test_unordered_multimap(long &value)
{

    cout << "\ntest_unordered_multimap()...................... \n";

    unordered_multimap<long, string> str;
    char buf[10];

    clock_t startTime = clock();
    for(long i = 0; i < value; i++)
    {
        try{ // 当内存不够时,捕获异常
            snprintf(buf, 10, "%d", rand());
            //str.insert(pair<long, string>(i, buf)); // 只有 push_front() 方法,没有 push_back() 方法
            str.insert({i, buf});
        }
        catch(exception &p){
            cout << "i = " << i << " " << p.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds:" << (clock() - startTime) << endl;
    cout << "unordered_multimap.size():" << str.size() << endl;
    cout << "unordered_multimap.max_size():" << str.max_size() << endl;

    long target = get_a_target_long();

    startTime = clock();
    auto it = str.find(target);
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;
    if(it != str.end())
        cout << "find, value:" << it->second << endl;
    else
        cout << "Not found" << endl;
}
// ****************** unordered_multimap ********************//


int main()
{
    long target = 1000000;
    test_unordered_multimap(target);
    return 0;
}

10. 使用容器 set

// ****************** multiset ********************//
void test_set(long &value)
{

    cout << "\ntest_set()...................... \n";

    set<string> str;
    char buf[10];

    clock_t startTime = clock();
    for(long i = 0; i < value; i++)
    {
        try{ // 当内存不够时,捕获异常
            snprintf(buf, 10, "%d", rand());
            str.insert(string(buf)); // 只有 push_front() 方法,没有 push_back() 方法
        }
        catch(exception &p){
            cout << "i = " << i << " " << p.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds:" << (clock() - startTime) << endl;
    cout << "set.size():" << str.size() << endl;
    cout << "set.max_size():" << str.max_size() << endl;

    string target = get_a_target_string();

    startTime = clock();

    auto pItem = find(str.begin(), str.end(), target);
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;

    if(pItem != str.end())
        cout << "find:" << *pItem << endl;
    else
        cout << "Not found" << endl;

    startTime = clock();
    auto it = str.find(target);
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;
    if(it != str.end())
        cout << "find:" << *it << endl;
    else
        cout << "Not found" << endl;
}
// ****************** set ********************//


int main()
{
    long target = 1000000;
    test_set(target);
    return 0;
}

在这里插入图片描述
我们申请了 1000000 个元素,但是 set 实际元素个数为 32768。

11. 使用容器 map

//****************** map ********************//
void test_map(long &value)
{

    cout << "\ntest_map()...................... \n";

    map<long, string> str;
    char buf[10];

    clock_t startTime = clock();
    for(long i = 0; i < value; i++)
    {
        try{ // 当内存不够时,捕获异常
            snprintf(buf, 10, "%d", rand());
            str[i] = string(buf);
        }
        catch(exception &p){
            cout << "i = " << i << " " << p.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds:" << (clock() - startTime) << endl;
    cout << "map.size():" << str.size() << endl;
    cout << "map.max_size():" << str.max_size() << endl;

    long target = get_a_target_long();

    startTime = clock();
    auto it = str.find(target);
    cout << "find, milli-seconds:" << (clock() - startTime) << endl;
    if(it != str.end())
        cout << "find, value:" << it->second << endl;
    else
        cout << "Not found" << endl;
}

// ****************** map ********************//

int main()
{
    long target = 1000000;
    test_map(target);
    return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值