http://www.169it.com/article/3215620760.html
http://www.cnblogs.com/sharpfeng/archive/2012/09/18/2691096.html
在C++的STL庫中,要實現排序可以 通過將所有元素保存到vector中,然后通過sort算法來排序,也可以通過multimap實現在插入元素的時候進行排序。在通過 vector+sort進行排序時,所有元素需要先存入vector容器中,sort在排序時又需要將元素全部取出來再進行排序。multimap底層實 現為紅黑樹,因此元素在插入的過程中就實現了排序。那么到底哪一種排序速度更快呢?
下面有一個測試程序:
#include <vector>
#include <set>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
using
namespace
std;
double
time
() {
struct
timeval tv;
if
(gettimeofday(&tv, NULL) != 0)
return
0.0;
return
tv.tv_sec + tv.tv_usec / 1000000.0;
}
struct
Score {
string name;
double
score;
bool
operator <(
const
Score& right)
const
{
return
score < right.score;
}
};
int
main(
int
argc,
char
** argv) {
vector<Score> src;
for
(
int
i = 0; i < 10000000; i++) {
int
num =
rand
();
char
buf[32];
sprintf
(buf,
"%d"
, num);
Score score = { buf, num };
src.push_back(score);
}
{
double
stime =
time
();
vector<Score> res;
for
(vector<Score>::const_iterator it = src.begin();
it != src.end(); ++it) {
res.push_back(*it);
}
sort(res.begin(), res.end());
double
etime =
time
();
printf
(
"vector: %f\n"
, etime - stime);
}
{
double
stime =
time
();
multiset<Score> res;
for
(vector<Score>::const_iterator it = src.begin();
it != src.end(); ++it) {
res.insert(*it);
}
double
etime =
time
();
printf
(
"multiset: %f\n"
, etime - stime);
}
return
0;
}
|
程序運行結果為:
time
vector 4.776060
multiset 10.761023
|
在這個測試中,vector+sort排序比multiset(multimap實現基於multiset)快多了。快速排序是目前已知的所有排序算法中最快的排序算法,因此它比基於堆排序的multiset快。
在這個測試結果出來之前,大多數人都會毫無疑問地認為multiset排序要更快。這也是有原因的,快速排序速度雖然快,但是在實際的運行過程中,它需 要大量地拷貝元素,其拷貝操作的時間復雜度為o(NlogN),而基於紅黑樹的multiset在排序的過程中則避免了元素的拷貝。如果元素的內存占用空 間比較大,那么multiset排序的速度將比vector+sort快。為了測試這個結果,將上面測試程序中的結構體改為:
struct
Score {
string name1;
string name2;
string name3;
string name4;
double
score;
bool
operator <(
const
Score& right)
const
{
return
score < right.score;
}
};
|
然后重新編譯運行測試程序,測試結果為:
time
vector 12.955739
multiset 11.368364
|
這個測試結果和我們的預期一致。
總之,我們在使用STL的排序算法時,需要根據不同的元素構造來進行合適的選擇,如果都是比較簡單的元素,那么適合選擇vector+sort來進行排 序,對於由字符串構成的占用了比較大的空間的復雜元素,應該使用multiset。如果排序的元素的總個數比較少,那么選擇任意一種都可以。
list支持快速的插入和刪除,但是查找費時;
vector支持快速的查找,但是插入費時。
map查找的時間復雜度是對數的,這幾乎是最快的,hash也是對數的。
如果我自己寫,我也會用二叉檢索樹,它在大部分情況下可以保證對數復雜度,最壞情況是常數復雜度,而std::map在任何情況下都可以保證對數復雜度,原因是它保證存諸結構是完全二叉檢索樹,但這會在存諸上犧牲一些時間。
STL 中的 map 內部是平衡二叉樹,所以平衡二叉樹的性質都具備。查找數據的時間也是對數時間。 vector,在分配內存上一般要比 new 高效的多。
為什么說 hash_map 是對數級的?在不碰撞的情況下,hash_map是所有數據結構中查找最快的,它是常數級的。
如果對問題設計了足夠好的hash算法,保證碰撞率很低,hash_map的查找效率無可置疑。
另外,STL的map,它的查找是對數級的,是除hash_map外最高的了,你可以說“也許還有改進余地”,但對於99.9999%的程序員,設計一個比STL map好的map,我執悲觀態度。
STL的map有平衡策略(比如紅黑樹什么的),所以不會退化,不需要考慮數據本身的分布問題。只不過,如果數據本身是排好序的,用vector或heap會明顯的快些,因為它們的訪問比較簡單。
我 想沒必要懷疑stl::map的查找效率,影響效率最主要的因素是什么?算法,在查找問題上,有什么算法比RB_tree更好嗎?至少現在還沒有。不否 認你可以通過自己寫代碼,設計一個符合你需要的BR—TREE,比stl::map簡捷那么一點,但最多也就每次迭代中少一行指令而已,處理十萬個數據多 執行十萬行指令,這對你重要嗎?如果你不是在設計OS像LINUX,沒人會關注這十萬行指令花的時間。
rb-tree的時間花在了插入和刪除上,如果你不是對插入和刪除效率要求很高,你沒有理由不選擇基於rb-tree的stl::map。
大多數程序員寫不出比std::map更好的map,這是當然的。然而並不是std::map的所有特性都出現在我們的程序中,自己編寫的可以更適合自己的程序,的確會比std::map更快一些。
關於hash_map,它與map的實現機制是不一樣的,map內部一般用樹來實現,其查找操作是O(logN)的,這個沒有爭議,我就不多說了。
hash_map 的查找,內部是通過一個從key到value的運算函數來實現的,這個函數“只接受key作為參數”,也就是說,hash_map的查找 算法與數據量無關,所以認為它是O(1)級的。來這里的應該都是達人,可以參看《數據結構》。當然,事實總不這樣完美,再引一段前面我自已說的話,進一步 說明,以免誤會:
-----------------------------------------
在不碰撞的情況下,hash_map是所有數據結構中查找最快的,它是常數級的。
------------------------------------------
注意我的前提:“在不碰撞的情況下”,其實換句話說,就是要有足夠好的hash函數,它要能使key到value的映射足夠均勻,否則,在最壞的情況下,它的計算量就退化到O(N)級,變成和鏈表一樣。
如果說 hash_map 是所有容器中最慢的,也只能說:“最拙劣的hash函數”會使hash_map成為查找最慢的容器。但這樣說意義不大,因為,最湊巧的排列能使冒泡排序成為最快的排序算法。
BS: "對於大型容器而言,hash_map能夠提供比map快5至10倍的元素查找速度是很常見的,尤其是在查找速度特別重要的地方.另一方面,如果hash_map選擇了病態的散列函數,他也可能比map慢得多. "
ANSIC++在1998年之后就沒再有重大改變,並且決定不再向C++標准庫中做任何重大的變更,正是這個原因,hash table(包括hash_map)並沒有被列入標准之中,雖然它理應在C++標准之中占有一席之地。
雖然,現在的大多數編譯平台支持hash table,但從可移植性方面考慮,還是不用hash table的好。
hehe俺也來湊湊熱鬧。
1.有的時候vector可以替代map
比如key是整數,就可以以key的跨度作為長度來定義vector。
數據規模很大的時候,差異是驚人的。當然,空間浪費往往也驚人。
2.hash是很難的東西
沒有高效低碰撞的算法,hash_xxx沒有意義。
而對不同的類型,數據集,不可能有優良的神仙算法。必須因場合而宜。
俺有的解決方法是GP,可不是飯型,是遺傳編程,收效不錯。
你的百萬級的數據放到vector不大合適。因為vector需要連續的內存空間,顯然在初始化這個容器的時候會花費很大的容量。
使用map,你想好了要為其建立一個主鍵嗎?如果沒有這樣的需求,為什么不考慮deque或者list?
map默認使用的是deque作為容器。其實map不是容器,拿它與容器比較意義不大。因為你可以配置它的底層容器類型。
如果內存不是考慮的問題。用vector比map好。map每插入一個數據,都要排序一次。所以速度反不及先安插所有元素,再進行排序。
用 binary_search對已序區間搜索,如果是隨機存取iterator,則是對數復雜度。可見,在不考慮內存問題的情況下,vector比map 好。
如果你需要在數據中間進行插入,list 是最好的選擇,vector 的插入效率會讓你痛苦得想死。
涉及到查找的話用map比較好,因為map的內部數據結構用rb-tree實現,而用vector你只能用線性查找,效率很低。
stl還提供了 hash容器,理論上查找是飛快~~~。做有序插入的話vector是噩夢,map則保證肯定是按key排序的,list要自己做些事情。
HASH類型的查找肯定快,是映射關系嘛,但是插入和刪除卻慢,要做移動操作, LIST類型的使鏈式關系,插入非常快,但是查找卻費時,需要遍歷~~ , 還是用LIST類型的吧,雖然查找慢點,
先快速排序,然后二分查找,效率也不低