標準模板庫 STL 簡單總結


常用容器vector, list, map, set


(1.1)vector的頭文件
#include <vector>
using std::vector;
vector<int> v_ints;
std::vector<int> v_ints;

(1.2)vector的構造
vector<int> first;                                // empty vector of ints
vector<int> second (4,100);                       // four ints with value 100
vector<int> third (second.begin(),second.end());  // iterating through second
vector<int> fourth (third);                       // a copy of third


(1.3)vector成員函數:
c.at(idx) , 類似操作符[], 返回索引idx所指的數據的引用,如果idx越界,拋出out_of_range。
c.begin() 返回指向首部數據的迭代器。返回類型爲 vector<T>::iterator。
c.end() 返回指向尾部數據的迭代器,此迭代器不執行任何內容。
c.empty() 判斷容器是否爲空,返回類型bool。
c.capacity() 返回容器中數據個數,返回類型爲size_type。
c.max_size() 返回容器中最大數據的數量,返回類型爲size_type。
c.size() 返回容器中實際元素的個數,返回類型爲size_type。

STL容器的capacity屬性,表示STL在發生realloc前能允許的最大元素數,也可以理解爲預分配的內存空間。例如一個vector<int> v的capacity爲5,當插入第6個元素時,vector會realloc,vector內部數據會複製到另外一個內存區域。這樣之前指向vector中的元素的指針、迭代器等等均會失效。
max_size屬性和capacity不同,表示STL容器允許的最大元素數,通常,這個數是一個很大的常整數,可以理解爲無窮大。這個數目與平臺和實現相關,在我的機器上vector<int>的max_size爲1073741823,而string的max_size爲4294967294。因爲max_size很大~所以基本不會發生元素數超過max_size的情況,只需知道兩者區別即可。
並不是所有的容器都會發生realloc,List,Map/Multimap,Set/Multiset的元素在內存中散佈,不預分配內存,所以不會產生realloc的情況,對於這些容器,其capacity是無意義的,所以這些容器沒有capacity()成員函數,也沒有capacity屬性。

void resize(size_type sz, T c=T()), 重新分配大小;
    myvector.resize(5);
    myvector.resize(8,100); // eight of value = 100

c.front() 返回第一個數據的引用。比如vector<string>::front()返回的就是string的引用。
c.push_back(T) 在尾部加入一個數據,參數爲模板類型,是最常用的vector增長方式
c.pop_back() 刪除最後一個數據。原型void pop_back();
c.clear() 移除容器中所有數據。
c.erase(pos) 刪除pos位置的數據,返回下一個數據的iterator。
c.erase(beg,end) 刪除[beg,end)區間的數據,返回下一個數據的iterator。


list作爲非連續的存儲, 不提供[]操作符和at(index)等隨機訪問函數. 而Vector是類似數組的連續存儲空間, 具有比較強的隨機訪問能力, 所以Vector提供[]操作符.
但Vector不具有insert. 

(2.1)list的構造
list<int> first;                                // empty list of ints
list<int> second (4,100);                       // four ints with value 100
list<int> third (second.begin(),second.end());  // iterating through second
list<int> fourth (third);                       // a copy of third

int myints[] = {16,2,77,29};
list<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );


for (list<int>::iterator it = fifth.begin(); it != fifth.end(); it++)  
  cout << *it << endl;
(2.2)list成員函數:

Iterators:
  list::begin(), 返回list::iterator
  list::end(), 返回list::iterator, 注意遍歷的邊界是 != list::end();

Capacity:
  bool list::empty() const;
  size_type size() const;  return the number of elements in list
  size_type max_size() const;
  

Modifiers:
void pop_front():  Removes the first element in the list container, effectively reducing the list size by one.This calls the removed element's destructor.
void push_front(const T &x): Insert an element at begin,
void pop_back(): Remove the last element in the rear of list, and calls the removed element's destructor.
void push_back(const T &x):



Insert elements
iterator insert ( iterator position, const T& x );
void insert ( iterator position, size_type n, const T& x );


Erase elements
iterator erase ( iterator position );
iterator erase ( iterator first, iterator last );
Removes from the list container either a single element (position) or a range of elements ([first,last]). calling each element's destructor before.
注意earse的返回值, 返回(刪除後)剩餘接點元素的iterator, 不能用iterator++的方式遍歷刪除, 正確的刪除操作如下:
list<int> testlist;
// 增加:
for(int i=0; i<10; i++) testlist.push_back(i);
// 刪除:
list<int>::iterator it;
for(it = testlist.begin(); it != testlist.end() )
    testlist.earse(it);
// 如果list中的元素是類, 那麼要手動調用析構函數. 



Remove elements with specific value
void remove ( const T& value );
Removes from the list all the elements with a specific valueThis calls the destructor of these objects and reduces the list size by the amount of elements removed.
remove(T &x) 成員函數是刪除特定值的操作, 比如students.remove"Jim";


Clear content
void clear ( );
All the elements in the list container are dropped: their destructors are called, and then they are removed from thelist container, leaving it with a size of 0.


Sort elements in container
  void sort ( );
Sorts the elements in the container from lower to higher. The sorting is performed by comparing the elements in the container in pairs using a sorting algorithm.


Reverse the order of elements
void reverse ( );
Reverses the order of the elements in the list container. All iterators and references to elements remain valid.


Get allocator
allocator_type get_allocator() const;
Returns the allocator object used to construct the container.



(3.2)map簡介:
Map是STL的一個關聯容器,它提供一對一(其中第一個可以稱爲關鍵字,每個關鍵字只能在map中出現一次,第二個可能稱爲該關鍵字的值)的數據處理能力,由於這個特性,它完成有可能在我們處理一對一數據的時候,在編程上提供快速通道。這裏說下map內部數據的組織,map內部自建一顆紅黑樹(一種非嚴格意義上的平衡二叉樹),這顆樹具有對數據自動排序的功能,所以在map內部所有的數據都是有序的
  1. 自動建立Key - value的對應。key 和 value可以是任意你需要的類型。
  2. 根據key值快速查找記錄,查找的複雜度基本是Log(N),如果有1000個記錄,最多查找10次,1,000,000個記錄,最多查找20次。
  3. 快速插入Key - Value 記錄
  4. 快速刪除記錄
  5. 根據Key 修改value記錄。
  6. 遍歷所有記錄。

(3.2)map的構造:

std::map<int,string> name; // int 爲索引
std::map<char, int> first; // char 爲索引
first['a'] = 1;
first['b'] = 2;
map<char,int> second(first.begin(), first.end());
map<char,int> third(second); 

由上面的代碼可知map 可以通過[]操作符獲取元素, 類似vector的[]. 另外map::iterator也支持解地址(*) 和 指針調用符(->). 
map<Key,T>::iterator it;
(*it).first;             // the key value (of type Key)
(*it).second;            // the mapped value (of type T)
(*it);                   // the "element value" (of type pair<const Key,T>)
it->first;               // same as (*it).first   (the key value)
it->second;              // same as (*it).second  (the mapped value)
map的兩個成員map::first和map::second分別代表關鍵字和數據.


(3.3)map成員函數:

1、向map插入元素

第一種插入方式:
用insert插入pair元素 map1.insert(pair<int,string>(99,"Jim"));

第二種插入方式:
用insert插入type_value元素 map2.insert(map<int,string>::value_type(99,"Jim"));

第三種插入方式:
直接利用[]操作符 map3[99] = "Jim";

類似於"類構造函數的初始化語法", map3[99] = "Jim"的賦值也有效率問題, 
插入99時,先在Map中查找主鍵爲99的項,未找到,然後將一個新的對象插入Map,鍵是99,值是一個空字符串,插入完成後,將字符串賦爲"Jim"; 
該方法會將每個值都賦爲缺省值,然後再賦爲顯示的值,如果元素是類對象,則開銷比較大。用第二種插入type_value的方式更加具有效率.
實際上, map::value_type的類型就是pair<const KEY, T &t>.

map::insert()和 map::operator[]的另一個區別是, 如果key已經存在, insert()是無法成功插入元素的, 但是數組操作符[] 就可以覆蓋已存在的數據.

question: 實現map::operator=, 以及operator[]


2、查找並獲取map中的元素
下標操作符給出了獲得一個值的最簡單方法:
CString tmp = enumMap[2];
但是,只有當map中有這個鍵的實例時纔對,否則會自動插入一個實例,值爲初始化值。
可以使用Find()Count()方法來發現一個鍵是否存在。

int index = 99;
map<int,string>::iterator it = map1.find(index);
if(it != map1.end()) 
    cout << it->second << endl;
else
    cout << "find nothing" << endl;


3、刪除map中的元素
  void erase ( iterator position );
  size_type erase ( const key_type& x );
  void erase ( iterator first, iterator last ); 
Removes from the map container either a single element or a range of elements ([first,last)).
This effectively reduces the container size by the number of elements removed, calling each element's destructor.
  1. iterator erase(iterator it); // 通過一個條目對象刪除
  2. iterator erase(iterator first, iterator last); // 刪除一個範圍
  3. size_type erase(const Key& key); // 通過關鍵字刪除
clear()就相當於 enumMap.erase(enumMap.begin(), enumMap.end());

STL容器的析構:
STL容器在析構之前, 會先調用存儲對象的析構函數:

{
  widget w; // 構造函數
  vector<widget> vec;
  vec.push_back(w); // 複製構造函數
}
函數退出時會調用兩次~widget(), 如果widget的成員中有指針類型, 並且widget沒有實現拷貝構造, 那麼編譯器自動合成的拷貝構造只是進行了"淺拷貝", 只是複製了指針的值, 兩個對象的指針實際指向了同一個地方. 

如果STL容易裏存儲的是指針類型, 一定要在銷燬容器前, 手動釋放指針指向的內存.

示例1:
std::map<int, char*> m_map;
char *p = new char(1000);
m_map[0] =  p;

std::map<int, char*>::iterator it;
for(it=m_map.begin(); it != m_map.end(); ++it)
    delete (char*)(it->second);


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