map< pair<int,int> , int > m ;
Здесь pair.first
и pair.second
положительны и pair.second >= pair.first
.
Я хотел бы найти все итератор /s в map m
, что для данного ключа. Ключ представляет собой целое число, которое находится между парами, например, ключ равен 2, а пара - [2,5]
и [1,2]
и т.д.
например, m[1,3] = 10, m[3,5] = 6, m[1,8] = 9, m[7,8] = 15
то при поиске m.find(3)
return iterator для m[1,3]
, m[1,8]
, m[3,5]
Если ключа нет, он возвращает m.end()
.
Я не уверен, почему вы хотите это сделать, но в наши дни библиотека Boost Interval Container довольно способна.
Предполагая, что вы, возможно, хотели бы отслеживать общую (сумму) отображаемых значений для определенной точки, вы могли бы просто применить разделительный стиль разделения к вашим входным данным и прибыли:
#include <boost/icl/split_interval_map.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
namespace icl = boost::icl;
int main() {
using Map = icl::split_interval_map<int, int>;
using Ival = Map::interval_type;
Map m;
m.add({Ival::closed(1,3), 10});
m.add({Ival::closed(3,5), 6});
m.add({Ival::closed(1,8), 9});
m.add({Ival::closed(7,8), 15});
for (auto e : m) std::cout << e.first << " -> " << e.second << "\n";
std::cout << "------------------------------\n";
for (auto e : boost::make_iterator_range(m.equal_range(Ival::closed(3,3))))
std::cout << e.first << " -> " << e.second << "\n";
}
Это скажет нам:
[1,3) -> 19
[3,3] -> 25
(3,5] -> 15
(5,7) -> 9
[7,8] -> 24
------------------------------
[3,3] -> 25
Обратите внимание, как
[3,3]
является единственной единственной точкой, совпадающей как с данными [1,3]
и с [3,5]
от входных данных одновременно, и в результате мы получаем полураскрытые интервалы в комбинированный набор ([1,3)
, [3,3]
и (3,5]
).10+6+9
для всех трех интересующих вас интервалов.Итак, вы видите, что я переключил фокус вопроса на "Как?" к "Что?". Обычно это помогает сформулировать цель кода вместо конкретной механики.
Конечно, если бы вместо суммы, которую вам было бы интересно в среднем, минимуме или максимуме, вы, скорее всего, написали бы какую-то стратегию объединения.
Бонус Если вы захотите, вот как вы можете, по крайней мере, написать решение проблемы, поставленной в OP, используя Boost Icl: Live On Coliru. Хотя он не особенно эффективен, он прямолинейный и надежный.
O(N)
, а не O(log N)
, или я что-то упустил? (Я нашел похожее решение, которое вы показали, но жаль, что Boost.ICL не будет поддерживать логарифмическое решение).
если вам нужен только итератор для следующего значения, найденного на карте, вы можете использовать алгоритм std :: find_if следующим образом:
int key=2;
map<pair<int,int>, int>::iterator it =std::find_if(m.begin(),m.end(),
[key](pair<pair<int,int>,int> entry)
{
return (entry.first.first <= key)
&& (entry.first.second >= key);
}
);
cout << "the next value is: [" << it->first.first << "/";
cout << it->first.second << "] " << it->second << endl;
Нет способа избежать линейного поиска с начала карты, потому что если первый элемент равен {0, INT_MAX}, то он совпадает, а нужные элементы не обязательно находятся в смежном диапазоне, например, если у вас есть {1,3 }, {2,2} {3,5} вам нужен только первый и последний элементы, когда ключ равен 3.
Вы можете остановить поиск, когда достигнете элемента с first
большим, чем ключ.
Что-то вроде этого (непроверено):
typedef map< pair<int,int> , int > Map;
std::vector<Map::iterator>
find(int key, const Map& m)
{
std::vector<Map::iterator> matches;
for (Map::iterator it = m.begin(), end = m.end(); it != end && key <= it->first; ++it)
{
if (it.first >= key && key <= it.second)
matches.push_back(it);
}
return matches;
}
Вы можете превратить его в функтора и использовать find_if
но я не уверен, что это того стоит.
Если вы хотите, чтобы один итератор возвращался за звонок:
typedef map< pair<int,int> , int > Map;
Map::iterator
find(int key, const Map& m, Map::iterator it)
{
for (Map::iterator end = m.end(); it != end && key <= it->first; ++it)
{
if (it.first >= key && key <= it.second)
return it;
}
return m.end();
}
Map::iterator
find(int key, const Map& m)
{ return find(key, m, m.begin()); }
m.lower_bound({key+1,0})
Я думаю, что вместо итераторов вы могли бы хранить (и использовать) соответствующие ключи карты. Если это так, то код может выглядеть так:
#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
#include <utility>
int main()
{
std::map<std::pair<int, int>, int> m;
m[{ 1, 3}] = 10;
m[{ 3, 5}] = 6;
m[{ 7, 8}] = 15;
typedef std::map<std::pair<int, int>, int>::value_type value_type;
typedef std::map<std::pair<int, int>, int>::key_type key_type;
int search;
auto in_range = [&search]( const value_type &value )
{
return value.first.first <= search && search <= value.first.second;
};
search = 3;
std::vector<key_type> v;
v.reserve( std::count_if( m.begin(), m.end(), in_range ) );
for ( const auto &p : m )
{
if ( in_range( p ) ) v.push_back( p.first );
}
for ( const auto &p : v )
{
std::cout << "[ " << p.first << ", " << p.second << " ]" << std::endl;
}
return 0;
}
Выход
[ 1, 3 ]
[ 3, 5 ]
Учтите, что предполагается, что key.first меньше или равен ключу. Второй, где ключ является ключом к карте.
p.first > key
i
находится между двумя значениями пары?