C++總結7——STL基本原理和用法

1.STL的三種類型容器
順序容器:
vector 向量容器
deque 雙端隊列
list 鏈表

容器適配器:
stack 棧
queue 隊列
priority_queue 優先級隊列

關聯容器:
set/multiset 集合
map/multimap 映射表

2.各容器的底層實現
具體實現請參考侯捷的《STL源碼剖析》,此處不貼源碼,只是對底層實現做簡單介紹。

順序容器:
<1>vector 向量容器

vector底層是動態開闢的可2倍自增長的一維數組,默認不申請空間。
第一次向vector中增加元素時,開闢一個格子,以後如果內存不足,每次擴大2倍。因此,這種數據結構在剛開始內存增長時的效率很低。vector底層內存連續

<2>deque 雙端隊列容器

deque底層時動態開闢的一維可2倍自增長的二維數組,默認部申請空間。deque底層內存不連續

第一次向deque中增加元素時,一維開闢兩個格子,二維開闢的元素個數遵守以下規則:如果變量的類型<4096,開闢4096/sizeof(_Ty)個格子;否則開闢一個格子,格子大小爲sizeof(_Ty)。size=sizeof(_Ty) < 4096 ? 4096/sizeof(_Ty) : sizeof(_Ty);

因爲是雙端隊列,所以底層有兩個指針(_start和_finish)。_start和_finish都向最中間。頭插時,_start向上移動,尾插時,_finish向下移動。二維數組不夠用時,再開闢二維空間。如果二維已經開闢滿了,則一維成2倍增長(cur *= 2),並將二維空間移動到新的一維空間的最中間,減少push_front和push_back時,開闢內存和移動的次數(pos = cur/2 -1)。

<3>list
list的底層是雙向鏈表。對list的操作就是對鏈表的操作,所以list容器的添加和修改效率很高。list默認分配一個頭節點,在插入值的時候,動態的申請節點,掛在鏈表中。

容器適配器:
容器適配器底層沒有自己的數據結構,他們是對某種容器的代理。

<1>stack默認的底層數據結構是deque
<2>queue默認的底層結構是queue
<3>priority_queue默認的底層結構是用vector實現的大根堆

關聯容器:
關聯容器的底層是RBtree,key有序排列。對關聯容器的操作都是對紅黑樹的操作。插入元素時,最多調整2次;刪除元素時,最多調整3次。

set/multiset只保存key,set中key不能重複,multiset中key可以重複
map/multimap保存的是key-value,map中key不能重複,multimap中key可以重複

Boost庫中實現了hash_map和multimap,是用鏈地址法實現的哈希表,鏈表的每個元素保存的都是鍵值對。

3.各類型容器的操作接口函數

<1>vector
定義:vector<int> vec;
插入:vec.push_back(value); vec.insert(it, value);
刪除:vec.erase(it); vec.erase(vec.begin(), vec.end());
獲取首元素:vector::itreator it = vec.begin();
vector末尾後一個元素:vector::iterator it = vec.end();
迭代器運算:it++; it–; ++it; –it;

vector的reserver方法和resize的區別:
vec.reserver(size);//只開闢內存
vec.resize(size);//開闢空間並構建size個對象

這裏寫圖片描述

<2>deque
定義:deque<int> dq;
插入:dq.push_front(value); dq.push_back(value); dq.insert(it,value);
刪除:dq.erase(it); dq.erase(dq.begin(), dq.end());
獲取首元素:deque::itreator it = dq.begin();
deque末尾後一個元素:deque:;iterator it = dq.end();
迭代器運算:it++; it–; ++it; –it;

<3>list
定義:list <int> list1;
插入:list1.push_front(value); list1.push_front(value); list1.insert(it, value);
刪除:list1.erase(it); list1.erase(list1.begin(), list2.end());
切片函數:list.splice(list.begin(), list.end(), list2, list2.end());
//將list1從begin到end的節點都拼接到list2的最後面

<4>stack
定義:stack<int> st;
添加元素:st.push(value);
獲取棧頂元素:st.top();
刪除棧頂元素:st.pop();
判斷棧是否空:st.empty();
求棧的元素個數:st.size();

<5>queue
定義:queue<int> qu;
添加元素:qu.push(value);
獲取隊列首元素:qu.front();
獲取隊列尾元素:qu.back();
刪除對頭元素:qu.pop();
判斷隊列是否空:qu.empty();
求隊列元素個數:qu.size();

<6>priority_queue
定義:priority_queue<int, vector<int>> queue; 大根堆
priority_queue<int, vector<int>, greater<int>> queue; 小根堆
添加元素:queue.push(value);
獲取首元素:queue.top();
刪除首元素:queue.pop();
判斷隊列是否空:queue.empty();
求隊列的元素個數:queue.size();

<7>set/multiset
定義:set<int> myset;
插入:myset.insert(key);
刪除:myset.erase(it); myset.erase(key);
查找:myset.find(key);

<8>map/multimap
定義:map<int, int> mymap;
插入:mymap.insert(makepair(key, value));
mymap[key] = value;
刪除:mymap.erase(it); mymap.erase(key);
訪問:map<int, int> ::iterator it = mymap.begin();
cout<begin<<” “<second;

4.泛型算法
需要頭文件#include <algorithm>

常用泛型算法:
find(vec.begin(), vec.end(), value);
find_if(vec.begin(), vec.end(), bind1st(greater<int>(), num));

sort(vec.begin(), vec.end()); 即:sort(vec.begin(), vec.end(), less<int>());//從小到大
sort(vec.begin(), vec.end(), greater<int>);//從大到小

copy(vec1.begin(), vec1.end(), back_inserter(vec2));
copy(vec1.begin(), vec1.end(), inserter(vec2, vec2.end()));

unique(it.begin(), it.end()); ///刪除相鄰重複的元素,實則是將重複的元素挪到後面,返回值是指向重複的第一個元素的迭代器

5.STL和泛型算法的實際應用

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <iterator>
using namespace std;

int main()
{
    //默認構造一個int vector vec;
    vector<int> vec;

    //隨機添加10個1-100整數
    for(int i=0;i<10; ++i)
    {
        vec.push_back(rand()%100+1);
    }

    //從小到大排序
    sort(vec.begin(), vec.end());

    //打印容器
    vector<int>::iterator it1;
    for(it1=vec.begin(); it1!=vec.end(); ++it1)
    {
        cout<<*it1<<" ";
    }
    cout<<endl;

    //從大到小排序
    sort(vec.begin(), vec.end(), greater<int>());

    //打印容器
    for(it1=vec.begin(); it1!=vec.end(); ++it1)
    {
        cout<<*it1<<" ";
    }
    cout<<endl;

    //找到第一個小於50的數字,並打印出來,並刪除掉
    vector<int>::iterator it2 = find_if(vec.begin(), vec.end(), bind1st(greater<int>(), 50));
    cout<<*it2<<endl;
    vec.erase(it2);

    //找容器裏面有沒有60這個元素,找到的話打印出來,沒找到打印失敗信息
    vector<int>::iterator it3 = find(vec.begin(), vec.end(), 60);
    if(it3 == vec.end())
    {
        cout<<"don't find 60"<<endl;
    }
    else
    {
        vec.erase(it3);
    }

    //生成一個新的vector容器
    vector<int> vec2;

    //把vec1容器裏面的所有元素拷貝到新容器當中
    copy(vec2.begin(), vec2.end(), vec.begin());

    //打印新容器
    vector<int>::iterator it4;
    for(it4=vec.begin(); it4!=vec.end(); ++it4)
    {
        cout<<*it4<<" ";
    }

    cout<<endl;

    //清空舊容器裏面所有的元素
    vec.clear();

    return 0;
}

這裏寫圖片描述

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <iterator>
using namespace std;

int main()
{
    //新建一個vector int實例化,默認構造
    vector<int> vec;

    //隨機100個0-10之間的數字
    for(int i=0; i<100; ++i)
    {
        vec.push_back(rand()%10);
    }

    vector<int>::iterator it1;
    for(it1=vec.begin(); it1!=vec.end(); ++it1)
    {
        cout<<*it1<<" ";
    }
    cout<<endl;

    //給容器去重複的數字
    sort(vec.begin(), vec.end());
    vector<int>::iterator it2 = unique(vec.begin(), vec.end());

    for(it1=vec.begin(); it1!=it2; ++it1)
    {
        cout<<*it1<<" ";
    }
    cout<<endl;

    return 0;
}

這裏寫圖片描述

6.迭代器

迭代器的類型:
<1>正向迭代器 iterator
<2>逆向迭代器 reserver_oterator
<3>插入型迭代器
back_insert_iterator /back_inserter push_back(value)
front_insert_iterator /front_inserter push_front(value)
isert_iterator /inserter insert(it,value)

插入型迭代器的使用

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <iterator>
using namespace std;

int main()
{
    vector<int> v1;
    vector<int> v2;
    vector<int> v3;

    for(int i=0;i<10;++i)
    {
        v1.push_back(i);
    }

    for(int i=0;i<10;++i)
    {
        v2.push_back(i+10);
    }

    for(int i=0;i<10;++i)
    {
        v3.push_back(i+20);
    }

    copy(v2.begin(), v2.end(),back_inserter(v1));

    vector<int>::iterator it1 = v1.begin();
    for(; it1!=v1.end(); ++it1)
    {
        cout<<*it1<<" ";
    }
    cout<<endl;


    copy(v3.begin(), v3.end(), inserter(v1, v1.end()));
    for(it1 = v1.begin(); it1!=v1.end(); ++it1)
    {
        cout<<*it1<<" ";
    }
    cout<<endl;
    return 0;
}

這裏寫圖片描述

<4>流迭代器
istream_iterator
ostream_iterator

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <iterator>
#include <set>
using namespace std;


int main()
{
    set<int> myset;
    copy(istream_iterator<int>(cin), 
         istream_iterator<int>(), 
         inserter(myset, myset.begin()));
    copy(myset.begin(), myset.end(), 
         ostream_iterator<int>(cout, " "));
 }

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章