簡體   English   中英

為什么 std::binary_search 返回 bool?

[英]Why does std::binary_search return bool?

根據草案N4431 ,算法庫中的函數std::binary_search返回一個bool ,[binary.search]:

 template<class ForwardIterator, class T> bool binary_search(ForwardIterator first, ForwardIterator last, const T& value); template<class ForwardIterator, class T, class Compare> bool binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp);

要求[first,last)的元素e根據表達式e < value!(value < e)comp(e, value)!comp(value, e)進行分區。 此外,對於[first,last)所有元素ee < value意味着!(value < e)comp(e, value) implies !comp(value, e)

返回: 如果范圍[first,last)存在滿足相應條件的迭代器i ,則為true!(*i < value) && !(value < *i)comp(*i, value) == false && comp(value, *i) == false

復雜性:最多記錄2 個(最后一個 - 第一個)+ O(1) 次比較。

有誰知道為什么會這樣?

大多數其他通用算法要么返回元素的迭代器,要么返回一個迭代器,它等效於表示元素序列末尾的迭代器(即,在序列中要考慮的最后一個元素之后),這就是我想要的預期的。

這個函數的名稱在1994年版的STL中是isMember 我認為你同意具有該名稱的函數應該返回bool

http://www.stepanovpapers.com/Stepanov-The_Standard_Template_Library-1994.pdf

它在C ++中被分成多個不同的函數,因為推理它幾乎不可能分辨出為什么有人以這種或那種方式做某事。 binary_search將告訴您這樣的元素是否存在。 如果您需要知道它們的位置,請使用lower_boundupper_bound ,它們將分別給出開始/結束迭代器。 還有equal_range ,它同時為您提供開始和結束。


因為其他人似乎認為這很明顯是為什么它是以這種方式創造出來的,所以如果你不是亞歷山大·斯捷潘諾夫或與他合作的人,我會說我的觀點為什么很難/不可能回答。

可悲的是, SGI STL FAQ根本沒有提到binary_search 它解釋了list<>::size為線性時間或pop返回void推理。 看起來他們認為binary_search不夠特別,無法記錄它。

讓我們來看看@ user2899162提到的可能的性能改進:

您可以在此處找到SGI STL算法binary_search的原始實現。 看一下它可以簡化它(我們都知道標准庫中的內部名稱有多糟糕):

template <class ForwardIter, class V>
bool binary_search(ForwardIter first, ForwardIter last, const V& value) {
    ForwardIter it = lower_bound(first, last, value);
    return it != last && !(value < *it);
}

正如您所看到的那樣,它是以lower_bound形式實現的,並且具有相同的精確性能。 如果他們真的希望它利用可能的性能改進,他們就不會用較慢的方式來實現它,所以看起來他們這樣做的原因並不是這樣。

現在讓我們看看它只是一個便利功能

它只是一個便利功能似乎更有可能,但通過STL你會發現許多其他算法,這是可能的。 看看上面的實現,你會發現除了std::find(begin, end, value) != end;之外,還有更多的事情要做std::find(begin, end, value) != end; 但是我們必須一直寫這個並且沒有返回bool的便利功能。 為什么在這里,而不是所有其他算法呢? 這不是很明顯,也不能簡單地解釋。

總而言之,我發現它遠非顯而易見,並且不知道我是否能夠自信而誠實地回答它。

二進制搜索算法依賴於嚴格的弱排序。 意味着元素應該根據operator <或根據具有相同保證的自定義比較器進行分區。 這意味着對於給定查詢,不一定只能找到一個元素。 因此,您需要lower_boundupper_boundequal_range函數來檢索迭代器。

標准庫包含返回迭代器的二進制搜索算法的變體。 它們被稱為std :: lower_boundstd :: upper_bound 我認為std::binary_search返回bool背后的基本原理是,在等效元素的情況下返回什么迭代器並不清楚,而在std::lower_boundstd::upper_bound情況下,它很清楚。

也可能存在性能因素,因為理論上可以實現std::binary_search以在多個等效元素和某些類型的情況下更好地執行。 但是,標准庫( libstdc++ )的至少一個流行實現使用std::lower_bound實現std::binary_search ,而且,它們具有相同的理論復雜性。

這是一個返回迭代器的 C++20 二進制搜索替代方案:

template<typename RandomIt, typename T, typename Pred>
inline
RandomIt xbinary_search( RandomIt begin, RandomIt end, T const &key, Pred pred )
    requires std::random_access_iterator<RandomIt>
    &&
    requires( Pred pred, typename std::iterator_traits<RandomIt>::value_type &elem, T const &key )
    {
        { pred( elem, key ) } -> std::convertible_to<std::strong_ordering>;
    }
{
    using namespace std;
    size_t lower = 0, upper = end - begin, mid;
    strong_ordering so;
    while( lower != upper )
    {
        mid = (lower + upper) / 2;
        so = pred( begin[mid], key );
        if( so == 0 )
        {
            assert(mid == 0 || pred( begin[mid - 1], key ) < 0);
            assert(begin + mid + 1 == end || pred( begin[mid + 1], key ) > 0);
            return begin + mid;
        }
        if( so > 0 )
            upper = mid;
        else
            lower = mid + 1;
    }
    return end;
}

僅當開始和結束之間只有一個與鍵匹配的值時,此代碼才能正常工作。 但是,如果您進行調試並且未定義 NDEBUG,則代碼將在您的調試器中停止。

如果你想在一個值上得到一個迭代器,你可以使用std :: equal_range ,它將返回2個迭代器,一個在下界,一個在值范圍的上限,等於你正在尋找的那個對於。

因為唯一的要求是值被排序而不是唯一的,所以沒有簡單的“find”會在你正在尋找的一個元素上返回一個迭代器。 如果只有一個元素等於你要查找的值,那么兩個迭代器之間只有1的差異。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM