STL學習小記--順序容器

STL中的順序容器有:

  vector    //支持快速隨機訪問

  list       //支持快速插入刪除  

  deque    //雙端隊列

順序容器適配器:

  stack        //LIFO

  queue       //FIFO

  priority_queue //有優先級管理的隊列

 

我不是很明白adapter適配器的意思。這個詞太布宜諾斯艾利斯了。以前接觸到的有電源適配器,網絡適配器,等等,在我的腦子裏直接會被替換成另一個詞彙,比如變壓器,網卡之類的。估摸着大概就是特殊應用的工具這種意思。

言歸正傳, 重複造輪子一直以來都是我樂此不疲的事情,所以此番是第一次學習STL。

順序容器,按字面意思就是把一堆東西(按模板的定義)按順序存放起來。

作爲一個初學者,使用最多的就是數組。但是數組需要在初始化的時候就設置好大小。如果是動態會增加刪除的需求的話,就不好使用數組了。這個時候可以使用vector來替代。

一, vector

使用vector之前,需要引入它的頭文件

#include <vector>

然後是

using std::vector;

當然,不限麻煩可以不寫這句,只要可以在每次聲明vector的時候都std::vector<XXX> vec;

複製代碼
#include <iostream>
using namespace std;
#include <vector>
using std::vector;

struct Student
{
    int nCode;
    string strName;
};

int main()
{
    Student sts[] = {{4, "ddd"},{2, "bbb"},{6, "fff"},{3, "ccc"},{1, "aaa"},{5, "eee"}};
    vector<Student> vec(sts, sts+sizeof(sts)/sizeof(Student));
    vector<Student>::iterator iter = vec.begin();
    for(;iter!=vec.end();iter++){
        cout<<iter->nCode<<", "<<iter->strName<<endl;
    }
    system("pause");
    return 0;
}
複製代碼

vector有好幾個構造函數,其中一個可以很方便地將數組的副本轉化成vector,也可以從數組中選擇一個區間將副本轉換成vector。

然後使用iterator(迭代器)或者是下標可以快速地對容器中的元素進行訪問。

對,只是訪問。和數組一樣,下標只是用於訪問,增刪什麼的使用下標或是迭代器都是很大的錯誤哦。

使用迭代器的時候,如果要訪問第一個元素,可以使用vector的成員函數begin(),它將返回第一個元素的迭代器。然後使用*符號就能訪問第一個元素。簡直就像是一個指針嘛。使用成員函數end()將會返回最後一個元素的末尾,這個末尾只是表示迭代器到達容器尾端,並不是最後一個元素,可以用來判斷容器中的元素遍歷完畢。

對迭代器使用算術操作符可以調整迭代器的定位。比如要快速定位到中間的元素,可以這樣:

  iter = vec.begin()+vec.size()/2;

對vector元素使用push_back可以在末尾插入元素,其他諸如此類的方法,等需要用的時候自行選擇即可。

需要注意的是,每次對vector的元素進行增刪之後可能引起迭代器定位的變動,再次使用迭代器之前需要重新定位。

二, list

同vector一樣,使用前需要引入頭文件

#include <list>

using std::list;

list的操作方式和vector大同小異。比較大的區別就是對數據的快速增刪上面,顧名思義。

還有好用的就是,list多了一個sort成員函數,對元素進行排序。

上面的代碼示例中在容器裏亂序添加了幾個學生,下面,替換成list容器,並對他們進行排序。

複製代碼
#include <iostream>
using namespace std;
#include <list>
using std::list;

struct Student
{
    int nCode;
    string strName;
};

bool Compfn(Student x,Student y)
{
    if(x.nCode>=y.nCode)
      return true;
   else
      return false;
}

int main()
{
    Student sts[] = {{4, "ddd"},{2, "bbb"},{6, "fff"},{3, "ccc"},{1, "aaa"},{5, "eee"}};
    list<Student> lst(sts, sts+sizeof(sts)/sizeof(Student));
    //list<Student>::iterator iter = lst.begin();//在這裏的迭代器在排序之後定位會被更改
    lst.sort(Compfn);
    list<Student>::iterator iter = lst.begin();
    for(;iter!=lst.end();iter++){
        cout<<iter->nCode<<", "<<iter->strName<<endl;
    }
    system("pause");
    return 0;
}
複製代碼

sort函數是按照升序排序的, 如果已經有<符號類型的話,可以直接使用lst.sort()進行排序,沒有的話需要實現一下。

sort函數可以接受一個參數,像學生等自定義的類型無法判斷按什麼規則來排序,可以按照姓名的拼寫,可以按照學號,可以升序,可以降序等等。。。這個時候定義一個函數來決定這個規則,這個函數指針就是sort的參數。

比如上例的Compfn函數

該函數接受兩個參數, 前者x和後者y, 如果返回爲true則不會變換兩者的位置表示順序正確,反之返回false則表示順序不對,需要變換位置。此處可以更改邏輯,自定義排序規則,比如>=的時候返回true就是降序平排列了。

另外, 似乎list沒有提供下標訪問。要問爲什麼的話,此時的我只想使用STL,並不想看源碼,顧名思義鏈表的話隨機訪問的確不是很方便。

同理得其他

另外的順序容器也都差不多。最後談一下我學到的幾個小教訓。

在使用stack的時候想要遍歷stack,於是訪問一次top,彈出一個元素,同時還對計數器i進行++操作。結果查看的元素只有一半。。。這個計數器i++的操作真是多餘,是不動大腦的機械式勞動的產物。

還有一個bitset的東西很有意思, 因爲沒有系統學習泛型, 所以是第一次看到將泛型當做類似函數參數一樣使用的。

原來泛型的還可以寫成bitset<32>這樣。。。爲什麼不乾脆設計成普通類的構造函數呢?這很奇怪。還有這樣的泛型也自己模仿着寫了一下,發現使用template<int n>這樣是沒問題,但如果是自定義類型的話(比如template<Student stu>)就不行。

複製代碼
template<Student stu>
class Person
{
    int m_numb;
public:
    Person()
    {
        m_numb = stu->nCode;
        cout<<m_numb;
    }
};


int main()
{
    Student stu = {10};
    Person<stu> p;//error
    return 0;
}
複製代碼

要說爲什麼的話:

可以去學習下C++primer的16.2.1節。

修改成如下就沒問題了。

複製代碼
template<Student* stu>
class Person
{
    int m_numb;
public:
    Person()
    {
        m_numb = stu->nCode;
        cout<<m_numb<<endl;
    }
};

Student stu = {10};

int main()
{
    stu.nCode = 100;
    Person<&stu> p;
    system("pause");
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章