c++之STL模板,set與map


為什么把set與map放在一起呢,因為里面有很多一樣的特性與結構;

一,set集合

原理:

  set里面的數據存放,不是數組模式,也不是指針鏈表模式,而是二叉樹模式,和map也是二叉樹模式,所以把set和map放在一起,這個二叉樹,不是簡單的二叉樹,就查找二叉樹與平衡二叉樹的結合題,紅黑樹!

  查找二叉樹(BST):左兒子的值比我小,而右兒子的值比我大,宏觀,我的左子樹的值,都比我小,我的右子樹的值都比我大;這樣定義的用途是方便查詢,達到二分查找的效果;

 

 

 

  平衡二叉樹(AVL):左右兩邊的深度,相差不多;

  而兩者都各有優點,缺點,設想,如果查找二叉樹中,根結點成為最大的值,那么其他的結點,都在該結點的左邊,這樣就達不到快速查找的效果,為了解決這個問題,就把查找二叉樹和平很二叉樹結合起來,到底如何保持樹的平衡呢?於是引入顏色來辨別樹是否歪曲;

  

 

  給紅黑樹四個原則,遵守這四個原則就可以構建紅黑樹:

  (1)根節點為黑色;

  (2)葉子結點為空值的黑色結點;

  (3)紅色結點的兩個子節點必須為黑色(紅黑紅黑樹)

  (4)所有葉子結點到根結點的路徑中,黑色結點個數要一樣;

 

   由原則3知道,不會有兩個連續的紅色結點;由原則4可知,紅黑樹中最短的路徑就是全黑色的結點,而最遠的路徑就是“黑-紅-黑-紅-黑-紅‘,那么如果假設黑色結點個數為:n,那么最短路徑長為n-1,最長為2*n-1,這樣就確保了紅黑樹中,最長的路徑不會超過最短路徑的兩倍;

  那么在插入和刪除結點的過程中,會影響紅黑樹的結構,甚至打破平衡,在插入的時候,默認為紅色結點,進行原則判斷,不滿足原則,則改變顏色,如果還不滿足條件,則進行子樹選擇,右選擇和左選擇,與AVL選擇一樣;

  而查找和修改結點的值,則是與普通二叉樹相同,指針指向這個值進行讀取(但是修改,結點的位置可能發生改變,所以,化歸,改變一個值,就是刪除原來的點,然后增加一個新的結點,有的編譯器支持修改,有的不支持修改)!

  了解了set的底層數據結構紅黑樹后,我們介紹set的具體使用;

迭代器原理:新增一個頭節點,left指向最小的紅黑樹中值最小的結點,而right指向紅黑樹中值最大的結點,parent指向根結點,頭節點之際的地址存為end(),所以,正向訪問和逆向訪問,都是從begin(),或者rbegin(),都是從頭節點的左右指針出發,最后返回來自己本身;那么++和--操作就是指針的移動,采用中序遍歷,返回到父節點(細節划分,可以分為4種情況)

color顏色域 left左指針 parent父指針 right右指針 data數據域

 

特性

  與其他STL模板相比,該數據結構特點在於,插入的值,會自動形成順序,所以你不用關心插入的位置在哪里,它會自動安排,然后就是不允許插入重復的值(multiset允許插入相同的值)

  綜上所訴,兩個特性:(1)自動排序(從小到大);(2)不允許重復值

功能

  傳統方法:增加,刪除,查找;

  set<int> p;

  增加:p.insert(i);直接放入值就可以;

  刪除:p.erase(i)刪除值為i的結點,也可以放入指針指向的值;本質相同(底部原理都是通過find找到再處理)返回結果為0或者1,1為刪除成功,0為刪除失敗,未找到;

  查找:p.find(i)放入要查找的目標值,返回結果為指針,如果未找到就是返回p.end()指針了,找到了,就是返回指向這個值的指針;

小實驗:

 1 #include<iostream>
 2 #include<set>
 3 using namespace std;
 4 int main() {
 5     set<int> p;    //聲明
 6     //插入;(10個)
 7     for (int i = 0; i < 10; i++) {
 8         p.insert(i);
 9     }
10     //遍歷查看;因為set是鏈表,所以不能用下標訪問;只能用迭代器指針;
11     for (auto it = p.begin(); it != p.end(); it++) {
12         cout << " " << *it;
13     }cout << endl;
14     //刪除   參數是里面的值,如何這個值不存在會出現什么?
15     cout <<"刪除8返回值:"<< p.erase(8) << endl;
16     cout << "刪除100(不存在)返回值:"<<p.erase(100) << endl;
17     for (auto it = p.begin(); it != p.end(); it++) {
18         cout << " " << *it;
19     }cout << endl;
20     cout << *p.find(9) << endl;//返回的是指向這個值的指針;
21     system("pause");
22     return 0;
23 }
set增刪查操作

 

優點:查詢快 自動排序 避免重復值

缺點:不能動態刪除;(刪除后,結構會發生變化,迭代器指向的位置,發生偏移) 不能索引訪問,

 

二,map集合

原理:底層原理和set一樣;不同之處就是data域,set的data域是個單獨的類型,而map的是通過pair打包形成一個結構體,是鍵:值的結構,而map的排序,是默認鍵從小到大排序的;而且在構建的時候,鍵對應的值默認為0;

特性:set擁有的特性,map全都有,而且因為特殊的結構,還重載了[ ]方便用戶操作,[]的底層其實就是find(),找到了就可以進去修改,如果沒有找到,可以通過[]插入新的值,刪除功能同樣是給出具體的值,然后查找,再刪除,而線性的數組式結構,就不能使用具體的值查找刪除,而是直接隨機訪問刪除,因為數組訪問起來比較慢,(!)

   而sort算法也是只對線性數組結構有效(vector,string)所以,對map進行另外的排序時,要通過vector的構建特性,把map導入vector,通過vector進行sort排序;

 

 

!<如何手寫實現set與map>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM