• STL浅析


    #include <iostream>
    #include <vector>
    #include <functional>
    #include <numeric>
    #include <algorithm>
    using namespace std;
    int main()
    {
        int ia[]={1,2,3,4,5};
        vector<int> iv(ia,ia+5);
        //cout<<accumulate(iv.begin(),iv.end(),1,multiplies<int>())<<endl;//120
        multiplies<int> mulObj;
        //cout<<mulObj(3,5)<<endl;//15
        sort(iv.begin(),iv.end(),greater<int>());//大数放在前
        modulus<int> modObj;//取余数(仿函数)
        cout<<modObj(3,5)<<endl;//3
    
        system("pause");
    
            return 0;
    
    }

    一.STL六大组件:

    1.容器:vector list deque map set multiset 

    2.算法(algorithm) sort search erase 

    3.迭代器 (iterator) 泛型指针

    4.配置器  (allocator) 负责空间配置和管理

    5.仿函数(functional) 重载

    6.配接器 修饰容器或仿函数或迭代器接口的东西

    二. 常用迭代器

    序列式容器:

    1.vector

    vector与数组类似,维护一个连续线性空间,支持随机存取,不同点是其是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素。其迭代器是普通指针,它以两个迭代器start和finish分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器end_of_storage指向整块连续空间(含备用空间)的尾端 
    为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求量更大一些——capacity,这里缺省采用前述的alloc空间配置器,同时据此另外定义了一个data_allocator,以方便以元素大小为配置单位:typedef simple_alloc<value_type,Alloc> data_allocator

    vector内存分配实现: 
    当push_back(x)将新元素插入vector尾端时,该函数首先检查是否还有备用空间,如果有就直接在备用空间上构造元素,并调整迭代器finish;如果没有,就扩充空间(重新配置、移动数据、释放原空间): 
    调用data_allocator::allocator重新配置一块大小为原空间两倍大小(若原空间为0,则新空间配置为1)的新内存空间 
    ——>调用uninitialized_copy将原vector的内容拷贝到新vector中,并对新元素设定初值x 
    ——>析构并释放原vector(destroy,deallocate) 
    ——>调整迭代器指向新的vector 
    由上述过程可知,针对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了

    2、map: 
    以红黑树为底层机制。 
    map所有元素都会根据元素的键值自动被排序。map的所有元素都是pair,同时拥有实值value和键值key。可表示为pair<key,value>。map同样不允许两个元素有相同的键值(它的插入操作采用的是底层机制RB-tree的insert_unique()),相同键值的元素插入不会被覆盖,若想键值不唯一,可使用multimap。

    不能通过map的迭代器改变map元素的键值,因为map元素的键值,关系到map元素的排列规则。如果任意改变map元素键值,会严重破坏map组织。但可以修正元素的实值。因此,map源码中迭代器既不是一种constant iterator,也不是一种mutable iterators。

    与list相同。当客户端对它进行元素新增操作或删除操作时,操作之前的所有迭代器,在操作完成之后都依然有效(除了被删除元素的迭代器)。

    定义形式:

        map<string,int>mymap;
        mymap[string("jihou")]=1;
        mymap.insert(pair<string,int>("jimmy",3));
        mymap["marry"]=6;
        mymap["marry"]=5;//将前值覆盖
        mymap["harry"]=5;//
        map<string ,int>::iterator it;
        it=mymap.begin();
        for (;it!=mymap.end();it++)
        {
            cout<<(*it).first<<"=>"<<(*it).second<<endl;
        }

    []操作符如simap[string(“jihou”)]既可以做左值,又可以做右值。如 
    int number = simap[string(“jihou”)]; 
    因此operator[]的返回值为引用,具体代码如下:

     T& operator[](const key_type& k) {

        return (*((insert(value_type(k,T()))).first)).second;
    }

     附:

    set/map底层为红黑树:

    红黑树: 树根始终为黑色 外部结点均为黑色  其余节点若为红色,则其孩子节点必为黑色     从任意外部结点待根节点的沿途,黑色节点数目相同

    为啥不用AVL树: 

    1. 单从查找、删除、插入等的时间复杂度来看,两者旗鼓相当,但因为AVL树对平衡条件要求更为严格,因此当进行操作时,AVL树进行调整的频率与次数要比红黑树高,也因此对于数据量较大插入或删除时或者数据复杂的情况,红黑树需要通过旋转变色操作来重新达到平衡的频度要小于AVL,因此红黑树比AVL(平衡二叉搜索树)具有更高的插入效率,虽然查找效率会平衡二叉树稍微低一点点,但是这种查找效率的损失是非常值得的。它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除。

    2. 此外,需要平衡处理时。红黑树比AVL树多一种变色操作,而且变色的时间复杂度在对数量级上,但因为操作相对简单,所以在实际应用中,这种变色仍然十分快速,对效率影响较小

    3. 当插入一个节点引起树的不平衡时,AVL和红黑树都最多需要2次旋转操作。但删除一个节点引起不平衡之后,AVL最多需要logN次旋转操作,而红黑树最多只需要3次。任何不平衡都会在3次旋转之内解决。因此两者插入一个结点的代价差不多,但删除一个结点的代价红黑树要低一些。

    4. AVL和红黑树的插入删除代价主要还是消耗在查找待操作的结点上。因此时间复杂度基本上都是与O(logN) 成正比的。

  • 相关阅读:
    类之间的关系:关联、组合、聚合、依赖关系比较
    贫血模型和充血模型
    WCF(五) 深入理解绑定
    WCF(四) 绑定
    WCF(四) 深入契约
    PythonStudy——函数默认值
    PythonStudy——函数的参数 Function argument
    PythonStudy——函数的返回值 The return value of the function
    PythonStudy——函数的分类 Classification of functions
    PythonStudy——函数的使用 Use of functions
  • 原文地址:https://www.cnblogs.com/zhaodun/p/7508870.html
Copyright © 2020-2023  润新知