c++STL

1.STLios

  [1]STL容器是直接管理存儲數據。編程

  [2]STL適配器是在這些容器上面增長一些操做函數,封裝成一個模板。數組

2.STL 容器app

  [1]容器類型:函數

    1)array:數組。ui

    2)bitset:二進制位操做。spa

    3)deque:雙向隊列。code

    4)forward_list:單向鏈表。對象

    5)list:雙向鏈表。blog

    6)map(multimap):map:鍵值非重複容器,multimap:鍵值可重複容器。 

    7)set(multiset):自動排序非重複集合。

    8)vector:動態數組。

    9)unordered_set(unordered_multiset):按照hash來存儲的set(multiset)。

    10)unordered_map(unordered_multimap):按照hash來存儲的map(multiset)。

  [2]容器的分類:

    1)容器分爲順序容器和關聯容器。

    2)順序容器是不進行自動排序的,關聯容器是按照元素的值進行自動排序的。其中map和set是關聯容器,其餘的是順序容器,最主要的就是關聯容器有find方法,能夠快速查找元素。

  [3]順序容器的使用說明:

    1)除了array是固定大小外,其餘容器都提供自動內存管理。

    2)string和vector保存在連續內存中,所以隨機訪問很快,可是在中間插入刪除會很慢。

    3)deque隨機訪問很快,而且在兩端插入刪除很快,可是在中間插入刪除會很慢。

    4)list和forward_list在任何地方插入刪除很快,隨機訪問很慢。

  [4]關聯容器的使用說明:

    1)map的使用,map是一個鍵值對,其中值是一個pair對象:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <arpa/inet.h>

using namespace std;

class ca
{
public:
    int ip;
};

class comp{
public:
    bool operator()(const ca &a, const ca &b) 
    {
        return a.ip < b.ip;
    }
};

bool operator<(const ca &a, const ca &b)
{
    return a.ip < b.ip;
}

int main()
{
    //map的第三個參數,另外第三個參數使用普通函數時編譯不過不知怎麼回事
    ca a1, a2, a3;
    map<ca, string> addr2;            //使用全局的<運算符重載函數
    map<ca, string, comp> addr1;    //使用仿函數

    addr1.insert(pair<ca, string>(a1, "1 addr a1"));
    addr2.insert(pair<ca, string>(a1, "2 addr a1"));


    //pair的使用
pair<ca, string> p1(a1, "1 addr a1"); //建立一個pair對象 addr1.insert(p1);
addr1.insert(pair<ca, string>(a2, "1 addr a2")); //隱式的建立一個pair對象,這個是經常使用的方式,由於一般沒有一個現成的對象 addr1.insert(make_pair(a2, "1 addr a3")); //調用make_pair建立一個pair對象 //關聯容器定義的類型 /* map的元素類型是一個pair對象,這個很重要。 元素: map的元素就是map容器裏面的一個值。就像是set<int>的每一個元素是一個int型對象。 關鍵字: map的關鍵字是pair對象的第一個元素。 */ map<ca, string>::key_type v1; //v1的類型是類ca,表明關鍵字的類型 map<ca, string>::mapped_type v2; //v2的類型是string,表明關鍵字關聯的類型 map<ca, string>::value_type v3; //v3的類型是pair<ca, string>,表明值的類型 set<string>::key_type v4; //v4和v5的類型是string,set的鍵值類型是同樣的 set<string>::value_type v5; return 0; }

    2)關鍵字類型必須定義元素的比較方法,這個是確定的,不然沒法進行排序。實際編程中,若是一個類定義了<運算符,就能夠做爲關鍵字了,這個意思就是說關鍵字沒有必要實現>和=運算符,實現了和不實現效果是同樣的。還有就是定義<運算符要符合嚴格弱序的規則,這意思就是自定義的<運算符函數,實現要合理,例如傳給這函數一個(a,b),返回true,傳給一個(b,a),仍是返回true,那就不符合嚴格弱序了。雖然不符合可是不會致使編譯錯誤,只是用的時候會發生各類錯誤,例如set插入了相同的元素。

      嚴格弱序規則就是:(1)若是傳入(a,b)返回true,則傳入(b,a)必須返回false。

                 (2)若是傳入(a,b)返回true,傳入(c,a)返回true,則傳入(c,b)必須返回true。就是說a<b,c<a,則c要小於b。

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <arpa/inet.h>

using namespace std;

class ca
{
public:
    unsigned ip;
    int port;
    ca(int ip1, int port1) {ip = ip1; port = port1;}

    //怎麼定義<運算符都是能夠的,看需求。
    //只是定義不一樣時,元素的排序順序是不同的。

    //若是用這種方式,則set裏面的排列順序爲:
    //    1.1.1.1:80
    //    1.1.1.1:81
    //    1.1.1.2:80
    //    1.1.1.2:81
    //        
    //這意思就是用ip去比較地址,若是ip不一樣時再用port去比較地址,固然使用這種需求通常用的比較多,這種方讓元素之間有一層優先級。
    bool operator<(const ca &other) const{
        if(ip < other.ip) 
            return true;
        else if(other.ip < ip) 
            return false;

        if(port < other.port) 
            return true;
        else if(other.port < port) 
            return false;

        return false;
    }
    
    //徹底等同於上面的函數
    bool operator<(const ca &other) const{
        if(ip < other.ip ||(ip == other.ip && port <other.port)) 
            return true;

        return false;
    }
    
    //若是用這種方式,則set裏面的排列順序爲:
    //    1.1.1.1:80
    //    1.1.1.2:80
    //    1.1.1.1:81
    //    1.1.1.2:81
    //這意思就是說但願用ip或port去比較地址,只要有一個小於就是小於,很明顯這種方式用的少。
    bool operator<(const ca &other) const
    {
        if(ip < other.ip || port < other.port) 
            return true;

        return false;
    }

    //錯誤的方式,錯誤的函數不會致使編譯錯誤,可是處理的時候會發生錯誤。例以下面這種就能夠把相同的數據插入到set裏面。
    //很明顯已經違背了嚴格弱序的原則,由於a < b爲true的時候同時b < a也爲true。
    bool operator<(const ca &other) const{
        return true;
    }
};

int main()
{
    set<ca> v;
    set<ca>::iterator it;

    v.insert(ca(inet_addr("1.1.1.1"), 80));
    v.insert(ca(inet_addr("1.1.1.1"), 81));
    v.insert(ca(inet_addr("1.1.1.2"), 80));
    v.insert(ca(inet_addr("1.1.1.2"), 81));

    for(it=v.begin(); it!=v.end(); it++)
        printf("%s:%d\n", inet_ntoa(*((struct in_addr *)&(it->ip))), it->port);

    return 0;
}

    3)set的迭代器是const的,就是說不能經過一個set迭代器去修改一個值,這個也是固然的,由於set是有序的,修改了就無序了,同理map的key值也是不能經過迭代器修改的,可是map的value是能夠經過迭代器修改的。

    4)map和set的insert操做能夠檢查返回值,判斷是否插入成功,例如元素已經存在則insert會失敗,返回的pair類型的第二個值爲false。

    5)lower_bound和upper_bound:這兩個操做都返回一個迭代器,若是關鍵字在容器中,lower_bound返回的迭代器指向第一個元素,upper_bound返回的迭代器指向最後一個位置的以後;若是關鍵字不在容器中,則lower_bound和upper_bound返回相同的位置,這個位置就是不影響排序的關鍵字的插入位置。若是存在則只要(begin=lower_bound;begin!=upper_bound;begin++;)就能夠遍歷這個關鍵字對應的全部元素。若是不存在,則返回的迭代器指向的位置是要查的關鍵字能夠插入的位置。

    6)multimap的使用(想必multiset的用法也是差很少的)例:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <arpa/inet.h>

using namespace std;

/*
    查找mulimap關鍵字的方法
*/
int main()
{
    // 1.使用lower_bound和upper_bound
    multimap<int, string> m;
    multimap<int, string>::iterator begin, end;

    m.insert(pair<int, string>(1, "boy1"));
    m.insert(pair<int, string>(2, "girl1"));
    m.insert(pair<int, string>(2, "girl2"));
    m.insert(pair<int, string>(2, "girl3"));
    m.insert(pair<int, string>(5, "dog1"));
    m.insert(pair<int, string>(5, "dog2"));

    /*
        輸出:
            key 2 value:girl1
            key 2 value:girl2
            key 2 value:girl3
            end value:dog1
        可見begin指向(2, "girl1"),end指向(5, "dog1")。
    */
    begin = m.lower_bound(2);
    end   = m.upper_bound(2);
    while(begin != end){
        printf("key 2 value:%s\n", begin->second.c_str());
        begin++;
    }
    printf("end value:%s\n", end->second.c_str());

    /*
        輸出:
            begin value:dog1
            end   value:dog1
        可見begin 和end都指向(5, "dog1"),由於此位置就是要查的關鍵字3應該插入的位置。
    */
    begin = m.lower_bound(3);
    end   = m.upper_bound(3);
    printf("begin value:%s\n", begin->second.c_str());
    printf("end   value:%s\n", end->second.c_str());

    /*
        輸出:
            begin value:0x7fff4e76b578
            end   value :0x7fff4e76b578
            m.end value:0x7fff4e76b578
        可見begin 和end都指向m.end(),由於此位置就是要查的關鍵字10應該插入的位置。
    */
    begin = m.lower_bound(10);
    end   = m.upper_bound(10);
    printf("begin value:%p\n", begin);
    printf("end   value:%p\n", end);
    printf("m.end value:%p\n", m.end());


    // 2.使用count方法獲得個數
    int count;
    multimap<int, string>::iterator it;
    
    count = m.count(5);    //獲得關鍵字5的元素個數
    it = m.find(5);     //指向關鍵字5的第一個元素

    /*
        輸出:
            key 5 value:dog1
            key 5 value:dog2
    */
    while(count > 0){
        printf("key 5 value:%s\n", it->second.c_str());
        it++;
        count--;
    }

    // 3.使用equal_range
    pair<multimap<int, string>::iterator, multimap<int, string>::iterator> range;
    
    range = m.equal_range(2); //直接獲得關鍵字2的迭代器的起始位置

    /*
        輸出:
            key 2 value:girl1
            key 2 value:girl2
            key 2 value:girl3
    */
    while(range.first != range.second){
        printf("key 2 value:%s\n", range.first->second.c_str());
        range.first++;
    }

    return 0;
}

    7)unordered_map和unordered_set:這兩個容器是無序的,就是說不是按順序存儲的。由於map和set都是自動排序的,例如遍歷map或set,能夠獲得按順序排序的值。可是unordered_map和unordered_set是按hash存儲的,遍歷會獲得不按順序輸出的值,因此若是要求存儲的元素有序就用map,若是無序而且須要快速查找,就用unordered_map。map和unordered_map效率比較的例子:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <arpa/inet.h>
#include <tr1/unordered_map>
using namespace std::tr1;

using namespace std;

double timeuse(struct timeval begin, struct timeval end)
{
    double res;
    
    if(end.tv_usec < begin.tv_usec){
        end.tv_usec += 1000000;
        end.tv_sec--;
    }

    res = end.tv_usec - begin.tv_usec;
    res += (end.tv_sec - begin.tv_sec)*1000000;
    return res;
}

int main()
{
    int i;
    
    map<int, int> m;
    map<int, int>::iterator it;
    unordered_map<int, int> um;
    unordered_map<int, int>::iterator uit;
    struct timeval tv_begin, tv_end;
    double res;

#define BEGIN   gettimeofday(&tv_begin, NULL);
#define END(s)  do{\
                    gettimeofday(&tv_end, NULL); \
                    res = timeuse(tv_begin, tv_end); \
                    printf("%-30s, usetime:%f usec [%f sec]\n", s, res, res/1000000);\
                }while(0)

    BEGIN
    for(i=0; i<10000000; i++)
        m.insert(pair<int, int>(i, i));
    END("map insert");

    BEGIN
    for(i=0; i<10000000; i++)
        um.insert(pair<int, int>(i, i));
    END("unordered_map insert");
    
    BEGIN
    it = m.find(500000);
    END("map find");

    BEGIN
    uit = um.find(500000);
    END("unordered_map find");

    return 0;
}

  輸出:

map insert                    , usetime:10102899.000000 usec [10.102899 sec]
unordered_map insert          , usetime:2749505.000000 usec [2.749505 sec]
map find                      , usetime:3.000000 usec [0.000003 sec]
unordered_map find            , usetime:1.000000 usec [0.000001 sec]

  因而可知unordered_map在插入和查找方面仍是比map要快不少的,固然內存佔用的也多。

3.STL適配器

  [1]stack:棧適配器。這個要注意的就是棧裏面是有一個容器來存儲元素的,常規的理解棧應該就是一個數組,其實不是,棧默認的容器是一個雙向隊列(deque),棧也能夠用vector、list等做爲元素的容器,有個條件就是容易須要提供push_back()、back()、和pop_back()方法,由於set沒有提供這些方法,因此不能把set做爲棧的容器。所謂棧就是在一個容器上面加了一些操做函數,封裝成了棧模板(STL中棧定義:template < class T, class Container = deque<T> > class stack;)。

  [2]queue:單向隊列適配器。這個和stack是同樣的,特色是先進先出。固然也是須要提供一個容器來存儲元素,默認是deque。

  [3]priority_queue :優先級隊列適配器。這個適配器是把容器內的元素排序好的,每次能夠獲取優先級最高的元素。因此能夠傳入一個優先級比較函數,默認比較函數是<,默認的容器是vector,定義方式priority_queue<Type, Container, Functional>。其實這個適配器只是在queue上面加了一個優先級排序函數。

4.STL具體用法

  [1]const_iterator:若是不須要寫訪問容器時,應該使用const_iterator迭代器,方法和iterator是同樣的。

  [2]reverse_iterator(const_reverse_iterator):能夠從後向前遍歷容器。

  [3]管理容量:除了array以外,容器的內存都是自動管理的。size()表示當前的元素數量,capacity()表示已經預分配的容量,reserve()表示設置預分配的容量。這個意思就是說capacity()是已經預分配好的容量,不論是程序自動分配仍是手動調用reserve()分配。還有就是resize()是設置容器使用的大小,和預分配沒有關係,例如當前元素個數是5,則resize(8)會往容器增長3個元素,resize(4)會刪除1個元素。

  [4]substr:拷貝原始string的一部分或所有。另外string類還提供了一些其餘方法,來完成和char *類型的字符串的處理函數,例如相似strstr、strrstr的函數。

  舉例:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <array>

using namespace std;

int main()
{
    vector<int> v;
    vector<int>::const_iterator c_it;
    vector<int>::const_reverse_iterator cr_it;

    v.push_back(1); v.push_back(2); v.push_back(3);v.push_back(4);v.push_back(5);

    //iterator對應的是begin、end
    for(c_it = v.begin(); c_it!= v.end(); c_it++)
        printf("%d\n", *c_it);

    //reverse_iterator對應的是rbegin、rend,cr_it = v.begin()是編譯不過的
    for(cr_it = v.rbegin(); cr_it!= v.rend(); cr_it++)
        printf("%d\n", *cr_it);

    // 容量設置
    printf("size:    %u\n", v.size());
    printf("capacity:%u\n", v.capacity());        //程序自動預分配的容量,例如值是8
    printf("--------------------------\n");

    v.reserve(20);                                //手動設置預分配的容量,若是值小於已經自動預分配的容量則不生效
    printf("size:    %u\n", v.size());
    printf("capacity:%u\n", v.capacity());        //此時值就是20了
    printf("--------------------------\n");

    v.resize(200);                                //強制設置元素個數是200                                 
    printf("size:    %u\n", v.size());            //值是200
    printf("capacity:%u\n", v.capacity());        //超過預分配的容量後,程序就會再次自動預分配

    //string操做
    string src("test string");
    string dst;

    // substr(pos, n)   pos默認是0,n默認是總長度,因此只傳一個參數的時候實際上是指定了拷貝的起始位置
    dst = src.substr(3);      
    printf("dst:%s\n", dst.c_str());             // dst:"t string" 
    dst = src.substr();      
    printf("dst:%s\n", dst.c_str());             // dst:"test string"

    return 0;
}

 5.C++手冊

  http://www.cplusplus.com/reference/

相關文章
相關標籤/搜索