1. 程式人生 > >STL中map與優先順序佇列

STL中map與優先順序佇列

先說說STL的容器一些常見的注意問題:有網友說,為什麼用了STL,程式的效率反而下降了呢?是的,如果用不好,你程式設計是方便了,可是效率下降了. 1: Vector,這個是基於線性陣列的容器 注意事項: 在宣告一個vector的時候,儘量指明大小,如果輸入資料不超過10^6,那就宣告一個10^6大小的vector,否則,vector的預設大小是10.(太小了),但是vector的大小可以自動擴大,不要以為僅僅是在已經分配的空間後面再多申請一塊,而是新開闢一塊空間,把原來的複製過去.想一下,如果你的vector不斷的擴容,不斷的複製,效率能不低嗎?這就是有的網友問為什麼STL的vector沒有陣列的效率高的原因. 2: Set, Map, 都是基於RB-Tree的容器,所以有自動排序功能 插入刪除,查詢效率都很高,查詢1000個記錄,最多查詢10次,查詢1000000個記錄,最多查詢20次 注意事項: 許多人喜歡用,但是如果頻繁的插入,刪除,不建議使用.因為每插入一次或者刪除一次,都要對RB-tree進行一次調整,n次插入,時間複雜度nlgn. 但是如果插入,刪除不頻繁的情況下是首選. 3: hash_set, hash_map, 都是基於hash_table的,沒有自動排序功能 注意事項: 在宣告的時候也要儘量指明大小,否則雜湊表的容量達到thresh_hold的時候要自動擴容,所有元素再雜湊一次.時間不容忽視. hash_table預設初始大小53, 然後擴容至97,193,389,故意是質數.預設的是樸素雜湊函式:比如"apple"的hash code: 5*(5*5*(5*'a'+'p')+'p')+'l')+'e' % 53 = 78066%53 = 50 目前hash_set hash_map都已經不再是標準的容器,namespace也從std move to stdext. Linux下名字空間是__gnu_cxx. (不推薦使用) 4: list: 雙向連結串列,記憶體空間不連續 只能用remove,remove_if, erase來刪除,inset插入,不可以直接修改pre,next.插入刪除效率比較高 5: deque 雙端佇列 分段連續記憶體空間,可以遍歷(提供iterator) 6: stack,queue 棧和佇列,唯一注意的是選擇底層容器,預設是deque,可以選擇list,vector,根據插入,刪除情況選擇合適的容器.(不同的底層容器擴容時帶來的效率影響), 二者均不提供iterator 7: priority_queue 優先順序佇列 (STL裡面最笨拙的容器) 基於堆,預設是大根堆,可以在建構函式裡面提供自己的比較函式實現小根堆. 不提供遍歷,不能查詢,不能修改裡面的元素,只提供top,push,pop 用A*搜尋的朋友注意了,新增新的子節點到openlist時,要判斷是否有重複節點,修改F值,這時才能體會到這個容器的笨拙之處. 8: Algorithm裡面提供了make_heap, push_heap, pop_heap, 如果單純做搜尋,能不用就不用了吧,pop_heap並沒有把元素彈出,而是放到了末尾. 適合對一個未排序的陣列進行堆排序使用. 其實我想說的是如果我們真的需要一個優先順序佇列,前提是我們能對這個優先順序佇列查詢,遍歷,修改(當然修改優先順序之後能自動排序),那就用map或者set來做吧.(取決於你要儲存的資料,前者是key,value對,後者只有key). 舉例如下: view plaincopy to clipboardprint? map> m; //最小的永遠處於前面 m[8] = 10; m[3] = 9; m[9] = 8; m[1] = 22; for(map>::const_iterator itor = m.begin();itor != m.end();itor++) printf("%d/n",itor->first); //輸出 1 3 8 9 m[5] = 100; for(map>::const_iterator itor = m.begin();itor != m.end();itor++) printf("%d/n",itor->first); //輸出 1 3 5 8 9 map> m; //最小的永遠處於前面 m[8] = 10; m[3] = 9; m[9] = 8; m[1] = 22; for(map>::const_iterator itor = m.begin();itor != m.end();itor++) printf("%d/n",itor->first); //輸出 1 3 8 9 m[5] = 100; for(map>::const_iterator itor = m.begin();itor != m.end();itor++) printf("%d/n",itor->first); //輸出 1 3 5 8 9 如果要修改優先順序怎麼辦呢? 反正修改之後也要對RB_tree進行調整,那就先remove掉,再放進一個新的,比如上面的例子我要把m[5]的優先順序改為10,可以如下方式: (注意,不可以直接修改key,map的iterator提供的key是隻讀的,也就是說itor->first是const的) view plaincopy to clipboardprint? int value = m[5]; m.erase(5); m[10] = value; for(map>::const_iterator itor = m.begin();itor != m.end();itor++) printf("%d/n",itor->first); //輸出 1 3 8 9 10 int value = m[5]; m.erase(5); m[10] = value; for(map>::const_iterator itor = m.begin();itor != m.end();itor++) printf("%d/n",itor->first); //輸出 1 3 8 9 10 以上是自己對STL做個小小的總結。 下面總結下STL中priority_queue的用法 在優先佇列中,優先順序高的元素先出佇列。標準庫預設使用元素型別的<操作符來確定它們之間的優先順序關係。優先佇列的第一種用法,也是最常用的用法: view plaincopy to clipboardprint? priority_queue qi; priority_queue qi; 通過<操作符可知在整數中元素大的優先順序高。故示例1中輸出結果為:9 6 5 3 2 第二種方法:在示例1中,如果我們要把元素從小到大輸出怎麼辦呢?這時我們可以傳入一個比較函式,使用functional.h函式物件作為比較函式。 view plaincopy to clipboardprint? priority_queue, greater >qi2; priority_queue, greater >qi2; 其中第二個引數為容器型別。第二個引數為比較函式。故示例2中輸出結果為:2 3 5 6 9 第三種方法:自定義優先順序。 view plaincopy to clipboardprint? struct node { friend bool operator< (node n1, node n2) { return n1.priority < n2.priority; } int priority; int value; }; struct node { friend bool operator< (node n1, node n2) { return n1.priority < n2.priority; } int priority; int value; }; 在該結構中,value為值,priority為優先順序。通過自定義operator<操作符來比較元素中的優先順序。在示例3中輸出結果為:優先順序 值 9 5 8 2 6 1 2 3 1 4 但如果結構定義如下: view plaincopy to clipboardprint? struct node { friend bool operator> (node n1, node n2) { return n1.priority > n2.priority; } int priority; int value; }; struct node { friend bool operator> (node n1, node n2) { return n1.priority > n2.priority; } int priority; int value; }; 則會編譯不過(G++編譯器)因為標準庫預設使用元素型別的<操作符來確定它們之間的優先順序關係。而且自定義型別的<操作符與>操作符並無直接聯絡,故會編譯不過。 //程式碼清單 view plaincopy to clipboardprint? #include #include #include using Namespace stdnamespace std; struct node { friend bool operator< (node n1, node n2) { return n1.priority < n2.priority; } int priority; int value; }; int main() { const int len = 5; int i; int a[len] = {3,5,9,6,2}; //示例1 priority_queue qi; for(i = 0; i < len; i++) qi.push(a[i]); for(i = 0; i < len; i++) { cout<