1. 程式人生 > >STL六大元件 之 容器 和 容器介面卡

STL六大元件 之 容器 和 容器介面卡

一、STL容器:

  • 順序容器:

(1)vector 向量容器,底層是由陣列實現的。

       初始化預設記憶體容量是0,有第一個元素時開闢一個元素大小,接下來的擴容以2倍的大小自動增長。(VS下是1.5倍)

       vector也可以在定義時直接指定空間大小和初始值:vector<type> iv(2,9);

       vetor擴充空間包括三個步驟:重新配置記憶體,移動資料,釋放原空間。所以一旦進行空間重新配置,使用者自己定義的指向原vector的所有迭代器就都失效了,而vector自帶的迭代器會被調整,指向新的vector。

       重新配置空間時,先確定空間大小,再通過空間配置函式去配置空間

       常用操作方法:begin()  end()

               size() 返回元素個數  

               capacity() 返回空間總大小  

               push_back(val)  插入一個元素   

               insert(it,n,val)  在it迭代器前插入n個val

               pop_pack()   從最後刪除一個元素  

               erase(it)  刪除it迭代器指向的元素     該操作會使it迭代器失效,但會返回it下一個元素的迭代器

               clear()  清除所有元素    

               erase(first,last)  刪除first和last之間的所有元素

(2)list 雙向連結串列容器,底層由雙向連結串列實現(含尾節點(為了保證迭代器的通用性))

       SGI list 是一個環狀雙向迴圈連結串列,所以只需要一個指標便可以表現整個連結串列。

       迭代器失效:list的插入(insert)和接合(splice)都不會造成迭代器的失效。

元素刪除(erase)只有指向被刪除元素的迭代器才會失效。

       常用操作方法:begin()   end()

         size()  返回當前節點個數(元素)

         push_back(val)  後插

         push_front(val)  前插

         pop_back()   後刪

         pop_front()   前刪

         insert(it,val)   在it迭代器之前插入值為val的節點

         erase(it)  刪除it迭代器指向的節點

         clear()   清除所有節點(整個連結串列)

         remove(val)  將val之前的所有元素移除

         unique()   移除連結串列中相同的連續元素,相同的只剩餘一個

         splice(it,list1)   將list1整個連結串列結合於it之前,不能是同一個list

         splice(it,list, it1)    將i所指元素結合於it之前,可以是同一個list

         splice(it,list,first,last)   將(first,last)內的所有元素接合到it之前

         merge(list1)    將list1 合併到 *this上,但兩個list都必須是遞增序列

         reverse()   將*this的內容逆向重置

         sort()  對元素排序,list自身的成員函式。因為通用演算法sort只接受隨機迭代器。

(3)deque  雙端佇列容器,底層用雙端佇列實現 【可以下標操作】

    緩衝區:實際存放資料的記憶體空間。大小預設為512bytes/sizeof(T),可以由使用者自行設定,

map:中控器 ,管理的節點數:最小為8,最多是 所需要節點數加2(所需節點數:(元素個數/每個緩衝區可容納的元素個數) +1 )。

當所有map結點都使用完了,一樣要進行空間的重新配置(配置更大的,拷貝原來的,釋放原來的)。

例:元素形態為int,緩衝區去大小為8的deque(指定了的deque<int,alloc,8>)。假設deque有20 個數據。所以就需要20/8 = 3個緩衝區,所以map使用了3個節點。

  資料結構如下:(空白是申請的空間,陰影部分為備用空間)

常用操作方法:pop_back()   pop_front()   clear()   erase(it)  erase(first,last)

                       push_back(val)   push_front(val)   size()   insert(it,val)

三者的比較:

vector和deque:①deque允許常數時間內對起頭端進行元素的插入和移除。vector的頭部插入和刪除效率是十分低的

②deque沒有容量的概念。因為deque是動態的以分段連續空間組合而成的,隨時可以增加一段新的空間並連線起來,不會因為記憶體不足而重新配置空間【一定情況下也需要重新配置空間:當map使用率已經滿載,便需要一塊更大的空間作為map,但相比vector的重新配置空間,deque對map的重新配置要比vector要代價小】

③deque的迭代器不是普通的指標,其複雜度遠遠大於vector,所以在運算層面上來說,vector要比deque的效率要高的多。

vector和list:list相對於vector和deque來說,對於任意位置的元素插入和刪除效率要遠遠大於其他兩個。

  • 關聯容器:

底層使用紅黑樹(平衡樹,排序樹,【資料有序】,add、delete、query(查詢)

時間複雜度都是O(log2n))

【所有元素會根據元素的鍵值自動被排序。】

(1)set   單重集合

     multiset  多重集合

性質:元素值就是鍵值。

set不允許有兩個相同的元素/鍵值,multiset允許有相同的元素/鍵值。

不可以通過迭代器改變set的元素值,因為set的元素值就是鍵值,改變鍵值會破壞set組織

元素刪除後只有指向被刪除元素的迭代器會失效。

       常用操作方法:

               增:insert(val);   時間複雜度: O(log2n)

               刪:erase(val);   時間複雜度: O(log2n)

               查:find(key);<--set的成員方法【原因與map一致】 時間複雜度: O(log2n)

      另一個重要方法:count(val);統計該值存在的個數,但在單重集合中不允許關鍵字重複

(2)map:對映表<key,value>  底層也能用雜湊表實現。根據key排序

     multimap :多重集合,允許key重複

       性質:同時擁有鍵值(key)和實值(value)。第一個元素是鍵值,第二個元素是實值。

                map不允許有兩個相同的鍵值。multimap允許有相同的鍵值。

                不可以通過迭代器修改map的鍵值,但可以修改實值。

元素刪除後只有指向被刪除元素的迭代器會失效。

       常用操作方法:

增:insert(make_pair(key,value));   O(log2n)

                       map[key] = value;  也可以使用下標的方式進行插入

                刪:erase(key);    O(log2n)

                查:find(key);<---map的成員方法     O(log2n)

               【map的成員方法是根據map的底層結構來進行實現的,效率自然比全域性的泛型演算法高】

              【順序容器沒有find的成員方法,因而只能用全域性的find演算法】

               STL還提供了一個通過val查詢的方法:find_if(first,last,pred);pred是用於比較數值的函式或者函式物件。

(3)hashtable:散列表  底層資料結構:以vector為buckets,以開鏈處理雜湊碰撞。

如圖:

     hashtable:bucktes的個數以28個質數為底。如:使用者定義一個n為50的hashtable,得到的散列表實際桶數量為53(第一個質數),這裡直接用vector下的空間申請函式reserve去處理,並用<vector>insert將恐案件初始化為0

對於插入元素操作,有兩個函式:①insert_unique,不允許key重複,②insert_equal,允許key重複。

      1)兩個插入在開始時都要先判斷是否需要重新建表。這裡呼叫resize<hashtable>函式,原則是:當元素個數(加上新增元素)大於“桶”的個數時,就重建表格。

重建表格當然首先要重新申請新的空間<大小為下一個質數>,將原buckets臉上的元素拷貝到新表中,然後新舊buckets對調,最後將舊錶釋放。

     2)插入新元素時,先要對新元素進行hash。這裡講hash function進行包裝,以_bkt_num函式為介面,該函式去呼叫bkt_bun_key函式,在bkt_num_key中將hash function得到的值進行取模運算。

所以hash function只需將原值返回即可,對char*型別字串則要進行特殊處理。

hash function是仿函式,過載operator()運算子,在該過載函式中進行值的返回即可。但也有部分型別未被過載,所以不可處理。

(4)hash_set、hash_map、hash_multiset、hash_multimap

     這四種關聯式容器,底層機制都是hashtable,元素不會被自動排序。

    除此之外他們與原身(set、map、multiset、multimap)的特性完全相同。當然hash_table不能處理的型別,他們也無法處理。

二、容器介面卡:

1、stack:棧  底層預設使用deque的資料結構,將一端封閉,實現後進先出的行為。

只能在頂端進行元素的插入、刪除、取得(get),所以不允許進行遍歷,沒有迭代器。

使用者也可以自己指定底層的資料結構,如:stack<int,list<int> >。這個stack底層使用的額資料結構就是list。因為list也是雙向開口的資料結構,所需的成員函式list也都有,所以以list為底部結構並封閉其埠開口,實現stack的先進先出特性。

              常用操作方法:

                     top 【返回棧頂元素】

                     push 【入棧,插到棧頂】

                     pop 【棧頂元素出棧】

                     size 【返回棧中元素的個數】

                     empty 【判斷棧是否為空】

2、queue:佇列  底層預設使用deque的資料結構,封閉低端的出口和頂端的入口,實現先進先出(從底端入,從頂端出的性質。

            因為只能從底端入,從頂端出,所以也不允許遍歷行為。沒有迭代器。

                     同理,使用者也可以自己指定queue的底層資料結構:queue<int ,list<int> >。用list作為queue的底層容器。

            常用操作方法:

                   push 【入隊插到隊尾】

                   pop 【隊首元素出隊】

                   size 【返回佇列中元素的個數】

                   front 【返回佇列中第一個元素】

                   back 【返回佇列中最後一個元素】

                   empty 【判斷佇列是否為空】

3、qriority_queue:帶權佇列  即queue中的元素不是按照被推入的次序排列,而是按照元素的權值(實值)排列,權值最高的,排在最前面。

       預設情況下qriority_queue底層使用max_heap(以vector)實現,可以滿足以“權值高低自動排序”的特性。

       與queue一樣,qriority_queue不提供遍歷的功能,也不提供迭代器。