【问题标题】:Why unordered_map::equal_range upper_bound returns end if a key is less than first map element如果键小于第一个地图元素,为什么 unordered_map::equal_range upper_bound 返回 end
【发布时间】:2019-09-14 18:33:30
【问题描述】:

我注意到 unordered_map::equal_range upper_bound (first) 如果传递的 key 小于 map 的第一个 key,则返回 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 的问题吗?

【问题讨论】:

  • 因为unordered_map 是,嗯,无序

标签: c++ stl unordered-map equal-range


【解决方案1】:

这是因为unordered_map 是无序的,这并不奇怪。

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

返回:包含所有元素的范围,其键等于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 的元素,则返回结束后(请参阅end())迭代器作为第一个元素。同样,如果没有大于key 的元素,则返回结束迭代器作为第二个元素。)

这种差异并不重要。 在任何一种情况下,您都应该简单地迭代 (first, second] 以检查您的元素(如果存在)范围,就像使用任何迭代器范围一样。

在您的代码中,您没有检查在您的 map 案例中返回的对的 both 部分。如果你这样做了,那么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)

【讨论】:

    猜你喜欢
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-20
    • 2019-06-01
    相关资源
    最近更新 更多