c++—STL(六大组件)

一、STL概述

 

        1.  STL概述

        (1)STL定义:STL(standard template library),标准模板库,是一个高效的c++程序库,重在提高了代码的复用性;主要包含了常用的数据结构和基本算法,为广大c++程序员提供了一个可扩展的应用框架;

        体现了泛型化(模板化)程序设计的思想,在实现方面是以一种类型程序参数化的方式实现的;采用模板类实现,所以定义时需要执行存储元素的类型(基本类型或自定义类型);

      2. STL的六大组件

        (1)容器(container):各种基本数据结构

        (2)迭代器(iterator):常使用在遍历容器,又可以用在连接容器和算法;

        (3)算法(algorithm):提供了各种基本算法如sort、search等;

        (4)适配器(adapter):可改变容器(containers)、迭代器(iterators)或函数对象(function object)接口的一种组件;

        (5)函数对象(function object):用类型包装函数,将函数类型化;

        (6)分配器(allocator):内部调用malloc分配空间;

c++—STL(六大组件)_第1张图片

 二、容器

        1. 分类:可分为三类:

        (1)顺序容器(sequence containers),主要包括array、vector、deque、list、forward_list;

        (2)关联容器(associative containers),内部机理是树、哈希表,元素是键/值对,特别适合做查找,因为其时间复杂度较低;且大都具有自动排序功能;主要包括set、multiset、map、multimap;

        (3)无序(散列)容器(UNordered containers),内部机理是哈希表,c++11里推出:元素的位置不重要,重要的是这个元素是否在这个容器里面,主要适用于查找;主要包括:underde_set、unordered_multiset、unordered_map、unordered_multimap;

c++—STL(六大组件)_第2张图片

        2. vector容器  头文件#include

        (1)本质与特点

        ①vector是内置有动态数组,可以随机存取元素,可用[ ] 和 at()方法;

        ②vector尾部添加或移除元素非常快速;

        ③因为vector在中间插入会导致后面的所有元素都要重新析构与拷贝构造,效率很低;

        ④vector采用模板类实现,所以定义时需要执行存储元素的类型(基本类型或自定义类型)

        (2)主要操作

vector对象的默认构造 vectorv1;
vector对象的带参数构造 vectorv2(v1.begin()+1, v1.begin()+4);
vector的插入 push_back、insert
vector数据存取 v1.at(), v1[ ], v1.front(),
vector的删除 pop_back(), clear(), erase(),
vector的迭代器 begin(), end(), rbegin(), rend()
vector的大小 size(), empty(), capacity(), resize(), shrink_to_fit
vector的赋值 assign(), operator=, swap

vector示例:

#include 
#include 
using namespace std;

class Test
{
public:
    Test()
    {
        // cout << "Test" << endl;        
    }

    Test(int t) : m_t(t)
    {
        // cout << "Test int" << endl;
    }

    Test(const Test &other)
    {
        m_t = other.m_t;
        // cout << "Test copy" << endl;
    }

    ~Test()
    {
        // cout << "~Test" << endl;
    }

    friend ostream& operator<<(ostream&out, Test &t);
    friend bool operator!=(const Test&t, int num);
    friend int operator%(const Test&t, int num);

    int m_t;
};
ostream& operator<<(ostream&out, Test &t)
{
    out<
void print(vector &vt)
{
    for(int i = 0; i < vt.size(); i++)
    {
        cout<
void delete_node(vector &vt)
{
    for(auto it = vt.begin(); it != vt.end(); )
    {
        
        if(*it % 2 != 0)
        {
            // it = vt.erase(it);
            vt.erase(it);
        }
        else
        {
            ++it;
        }
    }
}

int main(int argc, char **argv)
{
    vector vt;
    vt.reserve(20);  //提前预留20个元素值,避免了空间不够时,频繁的拷贝构造
    for(int i = 0; i < 9; i++)
    {
        vt.push_back(Test(i+1));  //连续构造1-10
    }

    print(vt);
    delete_node(vt);  //删除其中是基数的元素值(test的m_t是奇数的)
    print(vt);

    cout<<"vt.capacity() = "<  3. list 容器  头文件 #include

        (1)本质及特点

        ①list是一个双向链表容器,适合高效地在头尾插入或者删除元素;

        ②list不支持随机存取元素,所以不支持at()方式与[ ]操作符;请注意迭代器方面it++可以,但是it+2这样就不支持了;只可遍历,不可跳跃;

        (2)主要操作

list对象的默认构造 list l1;也可以是自定义类型;
list对象的带参数构造 list l2 (l1.begin()+1, l1.end());
list的插入

l2.push_back();     l2.pop_back();

l2.push_front();     l2.pop_front();

l2.emplace_back(); l2.emplace_front();

list元素删除

l2.clear(); 

l2.erase(beg,end);

l2.erase(pos);

l2.remove(elem);

l2.remove_if();

list.unique();

list的迭代器

l2.begin();

l2.end();

l2.rbegin();

l2.rend();

list的元素存取

l2.front();

l2.back();

list的赋值

l2.assign();

l2.swap(l1);

list的大小

l2.size();

l2.empty();

l2.resiae();

l2.resize();

list的排列

l2.sort();

l2.reverse();

list对容器的操作

splice();

list示例:

#include 
#include 
#include 

using namespace std;

template 
class Deleteor
{
public:
    bool operator()(const T &t)
    {
        return (t % 2) == 0;
    }
};

template 
void print(list & other)
{
    for(auto it = other.begin(); it != other.end(); ++it)
    {
        cout<<*it<<" ";
    }
        cout< l1;
    l1.emplace_back(1);
    l1.emplace_back(2);
    l1.emplace_back(3);
    l1.emplace_back(4);
    l1.emplace_back(5);
    l1.emplace_back(6);
    l1.emplace_back(7);
    l1.emplace_front(8);

    print(l1);  

    l1.insert(std::next(l1.begin(),3),9);  //std::next(l1.begin(),3)是制定插入的位置
    print(l1); 

    l1.remove(4);  //删除值等于4的元素
    print(l1);

    l1.remove_if(Deleteor());  //Deleteor()是删除的规则,返回的是bool(true,false)
    print(l1);                      //这里是一个函数对象,重载了函数运算符()

    l1.sort();  //对list排序,默认是从小到大
    print(l1);

    l1.sort(greater());  //内建函数(对象),实现从大到小排序
    print(l1);

    l1.reverse();  //对list逆序
    print(l1);

    listl2 = {1,3,5,7,9};
    listl3 = {2,4,6,8,10};
    l2.merge(l3);  //将l3合并到l2上,并按照默认的从小到大方式排好序
    cout<<"l2 : ";
    print(l2);
    cout<<"l3 : ";
    print(l3);  //l3会被清空

    listl4 = {7,7,7,7};

    auto it = l2.begin();
    std::advance(it,2);  //将it迭代器后退2个位置,-2就是前进2个位置
    l2.splice(it,l4);
    cout<<"l2 : ";
    print(l2);

    return 0;
}

        4. forward_list容器

        本质及特点:优化list产生的,forward_list是单向链表,这样的话少存储一个指针,节省系统开销;

        ①只提供前向迭代器,不支持反向迭代器;

        ②不提供size()成员函数;

        ③没有指向最末元素的锚点,因此不提供back(),push_back(),pop_back();

        ④不提供随机访问,与list同;

        ⑤插入和删除元素不会造成“指向其他元素的”指针、引用、迭代器失效;

        5. deque 容器,本质及特点:

        ①deque是双端数组,而vector是单端的;

        ②与vector一样,可以随机存取元素;且在头部和尾部移除元素都非常快速,但是在中间插入元素则比较费时;

        ③其他内容以vector一样;

        6. set/multiset 容器  头文件:#include

        (1)本质及特点

        ①set是一个集合容器,其中包含的元素是唯一的,集合中的元素按一定的顺序排列;元素插入过程是按排序规则插入,所以不能指定插入位置;

        ②set采用红黑树变体的数据结构实现,红黑树属于平衡二叉树,在插入操作和删除操作上比vector快;时间复杂度是O(log n);

        ③set不可以直接存取元素(不可以使用at.(pos)与[ ] 操作符);

        ④multiset与set的区别是:set支持唯一键值,即每一个元素只能出现一次;而multiset中的元素可以出现多次;

        ⑤不可以直接修改set或multiset容器中的元素值,因为这类容器是自动排序的,如果要修改其中的某个元素值,必须先删除原有的元素,再插入新的元素;

程序示例:

#include 
#include 
#include 

using namespace std;

template 
void print(const set &other)
{
    for(auto it = other.begin(); it != other.end(); ++it)
    {
        cout<<*it<<" ";
    }
    cout<si;
    si.insert(1);
    si.insert(3);
    si.insert(7);
    si.insert(5);
    si.insert(2);

    print(si);

    // auto node = si.extract(3);  //修改成员值,c++17,本系统不支持
    // node.value = 9;
    // si.insert(move(node));

    // sets2 = {2,4,6,8};
    // si.merge(s2);  //将s2合并到si,c++17,本系统不支持

    cout<<"si.count(5) : "< 7. map/multimap 容器  #include

        (1)本质及特点

        ①map是标准的关联式容器,一个map是一个键值对(一个序列号,一个值,相当于数组的索引和对应的值),它提供基于key(键值)的快速检索能力;键值对中第一个元素是first,第二个元素是second,支持迭代器访问输出;

        ②map中的key值是唯一的;集合中的元素按一定的顺序排列,元素插入过程是按排序规则插入,所以不能指定插入位置;

        ③map的具体实现采用红黑树变体的平衡二叉树数据结构,在插入和删除操作上比vector块;

        ④map可以直接存取key所对应的value,支持[ ] 操作符,如map[key] = value;

        ⑤multimap 与 map 的区别:map支持唯一键值,每个键只能出现一次,而multimap中相同的键可以出现多次。但是multimap不支持[ ]操作符;

        (2)示例

#include 
#include 
#include 

using namespace std;

template
void print(const map &other)
{
    for(auto it = other.begin(); it != other.end(); ++it)
    {
        cout<<"key : "<first<<" value : "<second< m1;  //和数组很像,索引+对应的值
    m1[1] = "hello1";
    m1[2] = "hello2";
    m1[3] = "hello3";

    print(m1);

    return 0;
}

        (3)一个面试题示例:给定一个数组,计算每个数值出现的次数,然后按字符出现次数的升序输出数值及其出现次数;并且单独输出个数大于数组个数一半的元素;

#include 
#include 
#include 

using namespace std;

template
void print(const multimap &other)
{
    for(auto it = other.rbegin(); it != other.rend(); ++it)
    {
        cout<<"降序遍历 : 值"<second<<"   次数:"<first< (len/2))
        {
            cout<<"符合要求:"<

结果:

c++—STL(六大组件)_第3张图片

        8. 容器的选择原则总结

        ①vector是内置有动态数组,当容量满时会自动扩充,在末尾有定位指针,所以末尾插入十分快速,但中间插入则较慢,因为涉及到原有数组的拷贝;最大的特点是适合高效的随机访问;而deque则优化为可以既可以头插也可以末尾插;

        ②list是一个双向链表容器,访问指定元素的效率较低,不支持随机访问,最大的特点是中间插入的效率较快;

        ③set是一个集合容器,元素具有唯一性,因为排序功能,所以开销较大;若需要支持重复数据则需要使用multiset;

        ④map是关联式容器,内置键值对,且内部按照顺序排序,内部采用红黑树的数据结构,时间复杂度是O(log n ),查找与删除的效率很高;适合字典式存储数据;

你可能感兴趣的:(c++语言学习,c++,开发语言,c语言,linux,算法)