[英]Why use std::less as the default functor to compare keys in std::map and std::set?
我想知道為什么std::map
和std::set
使用std::less
作為默認函子來比較鍵。 為什么不使用與strcmp類似的函子? 就像是:
template <typename T> struct compare
{
// Return less than 0 if lhs < rhs
// Return 0 if lhs == rhs
// Return greater than 0 if lhs > rhs
int operator()(T const& lhs, T const& rhs)
{
return (lhs-rhs);
}
}
假設map
有兩個對象,分別為key1
和key2
。 現在,我們要插入另一個具有鍵key3
對象。
使用std::less
, insert
功能需要首先使用key1
和key3
調用std::less::operator()
。 假設std::less::operator()(key1, key3)
返回false。 它必須在切換鍵std::less::operator()(key3, key1)
std::less::operator()
再次調用std::less::operator()
,以確定key1
等於key3
還是key3
大於key1
。 有兩次調用std::less::operator()
來確定第一個調用是否返回false。
如果std::map::insert
使用compare
,那么只需一次調用就可以提供足夠的信息來做出正確的決定。
根據映射中鍵的類型, std::less::operator()(key1, key2)
可能會很昂貴。
除非我缺少一些非常基本的知識,否則std::map
和std::set
是否應該使用諸如compare
之類的東西而不是std::less
類的默認函子來比較鍵?
我決定向Alexander Stepanov(STL的設計師)詢問有關此問題的信息。 我被允許引用他如下:
最初,我提出了三向比較。 標准委員會要求我改為使用標准比較運算符。 我做了我被告知的事情。 二十多年來,我一直主張將三路組件添加到標准中。
但是請注意,也許直覺上來說2路並不是很大的開銷。 您不必進行兩次比較。 在下降過程中,每個節點只是一個比較(無相等檢查)。 代價是無法提前返回(當密鑰位於非葉子中時),而最終無法進行一次額外的比較(交換用於檢查相等性的參數)。 如果我沒記錯的話
1 + 1/2*1 + 1/4*2 + 1/8*3 + ...
= 1 + 1/2+1/4+1/8+... + 1/4+1/8+... + ...
-> 3 (depth -> infty)
在包含查詢元素的平衡樹上平均進行額外比較。
另一方面,三向比較沒有可怕的開銷:無分支三向整數比較 。 現在,是否有一個額外的分支來檢查每個節點的0(相等)比較結果是否比在末尾進行約3個額外的比較要少開銷。這是另一個問題。 可能無關緊要。 但是我認為比較本身應該是3值的,以便可以更改是否使用所有3個結果的決定。
更新:請參閱下面的評論,以了解為什么我認為三向比較在樹中更好,但不一定在平面數組中。
基於樹的容器僅需要嚴格的弱總定貨。
參見https://www.sgi.com/tech/stl/StrictWeakOrdering.html
寫訪問
映射和集合的插入點完全由單個二進制搜索(例如lower_bound
或upper_bound
。 二進制搜索的運行時復雜度為O(log n)
讀取權限
這同樣適用於搜索:搜索是遠遠大於線性平等掃描更高效,正是因為不是最需要的元素並進行比較。 訣竅是容器是有序的。
結果是equality
信息不必存在。 只是,這些項目可以具有相等的順序 。
實際上,這僅意味着對元素類型的約束更少,實現需求的工作量減少以及在常見用法場景中的最佳性能。 總是會有權衡的。 (例如,對於大型集合,散列表( 無序集和映射)通常會更高效。請注意,這些equatable
確實需要equatable
元素,並且它們采用散列方案進行快速查找)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.