如果键小于第一个map元素,为什么unordered_map :: equal_range upper_bound返回end

问题描述 投票:2回答:2

我注意到如果传递的key小于map的第一个,则unordered_map :: equal_range upper_bound(first)返回end

#include <iostream>
#include <map>
#include <tr1/unordered_map>

using namespace std;

int main ()
{
    {
        std::map<char,int> mymap;
        mymap['c'] = 60;
        std::map<char,int>::iterator itup = mymap.equal_range('a').first;
        std::cout << "map::itup " << itup->first << std::endl;
    }

    {
        tr1::unordered_map<char, int> mymap;
        mymap['c'] = 60;
        mymap['d'] = 70;

        tr1::unordered_map<char, int>::iterator itlo = mymap.equal_range('a').first;
        tr1::unordered_map<char, int>::iterator itup = mymap.equal_range('a').second;

        cout << "unordered_map::itup " << (itup == mymap.end() ? "END" : "NOT END") << std::endl;
        cout << "unordered_map::itlo " << (itlo == mymap.end() ? "END" : "NOT END") << std::endl;
    }

    return 0;
}

输出是:

map::itup c
unordered_map::itup END
unordered_map::itlo END

请注意,map和unordered_map的行为是不同的 - 任何原因或unordered_map中的问题?

谢谢,亚历山大

c++ stl unordered-map equal-range
2个回答
2
投票

发生这种情况是因为unordered_map不太令人惊讶,无序。

有关Table 70的要求,请参见§22.2.7[unord.req],equal_range

返回:包含所有元素的范围,其中键的值等于k。如果不存在这样的元素,则返回make_­pair(b.end(), b.end())

这与有序关联容器的要求不同,例如std::map,其中equal_range是根据lower_boundupper_bound定义的。

由于显而易见的原因,std::unordered_map没有lower_boundupper_bound


2
投票

你要求的范围包括你的unordered_map中的所有元素,其关键是'a'。您的无序地图不包含此类元素。所以,范围是空的。

map案例也是如此。然而,这个条件的表示方式因容器而异(尽管不是真的;继续阅读)。容器std::mapstd::unordered_map不是一回事(因此它们有不同的名称)。前者是有序的,而后者则不是,因此出于逻辑实现的原因,它的工作方式略有不同:

unordered_map

Return value std::pair包含一对定义所需范围的迭代器。如果没有这样的元素,则将结尾(参见end())迭代器作为该对的两个元素返回。

map

Return value std::pair包含一对定义所需范围的迭代器:第一个指向第一个不小于key的元素,第二个指向第一个元素大于key。如果没有不小于key的元素,则返回last-the-end(参见end())迭代器作为第一个元素。类似地,如果没有大于key的元素,则返回结束迭代器作为第二个元素。)

这种差异无关紧要。无论哪种情况,您都应该迭代(firstsecond)来检查范围内的元素(如果存在),就像使用任何迭代器范围一样。

在您的代码中,您没有检查map案例中返回的对的两个部分。如果你那么you'll find that first == second(再次,表示空的范围)。

您的map代码有效地取消引用返回范围的“过去的”迭代器。


#include <iostream>
#include <map>
#include <unordered_map>

using namespace std;

int main ()
{
    {
        std::map<char,int> mymap;
        mymap['c'] = 60;
        std::map<char, int>::iterator itlo = mymap.equal_range('a').first;
        std::map<char, int>::iterator itup = mymap.equal_range('a').second;

        // This compares each range extent to the map's end, which is not really useful
        cout << "map::itup " << (itup == mymap.end() ? "END" : "NOT END") << '\n';
        cout << "map::itlo " << (itlo == mymap.end() ? "END" : "NOT END") << '\n';

        // This examines the range itself
        cout << "map range empty: " << (itlo == itup ? "YES" : "NO") << '\n';
        cout << "map range size: " << std::distance(itlo, itup) << '\n';
    }

    {
        std::unordered_map<char, int> mymap;
        mymap['c'] = 60;
        mymap['d'] = 70;

        std::unordered_map<char, int>::iterator itlo = mymap.equal_range('a').first;
        std::unordered_map<char, int>::iterator itup = mymap.equal_range('a').second;

        // This compares each range extent to the map's end, which is not really useful
        cout << "unordered_map::itup " << (itup == mymap.end() ? "END" : "NOT END") << std::endl;
        cout << "unordered_map::itlo " << (itlo == mymap.end() ? "END" : "NOT END") << std::endl;

        // This examines the range itself
        cout << "unordered_map range empty: " << (itlo == itup ? "YES" : "NO") << '\n';
        cout << "unordered_map range size: " << std::distance(itlo, itup) << '\n';
    }
}

// Output:
// 
// map::itup NOT END
// map::itlo NOT END
// map range empty: YES
// map range size: 0
// unordered_map::itup END
// unordered_map::itlo END
// unordered_map range empty: YES
// unordered_map range size: 0

(live demo)

© www.soinside.com 2019 - 2024. All rights reserved.