Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.88/76: Рейтинг темы: голосов - 76, средняя оценка - 4.88
155 / 137 / 46
Регистрация: 15.02.2010
Сообщений: 750
1

multimap (просмотр по ключу)

01.05.2020, 11:48. Показов 15655. Ответов 30
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте.
Имеется заполненный контейнер:
C++
1
multimap<int,int> mtp;
Нужно просмотреть все его значения по заданному ключу (например, 5)
Конечно, можно тупо перебрать все пары и выести значения по ключу:
C++
1
2
3
for(auto it = mtp.begin(); it != mtp.end(); it++)
if (it->first == 5)
cout << it->second;
Вопрос: Группируются ли в памяти элементы массива multimap по ключу?
Можно ли сделать последовательный просмотр через поиск типа такого:
C++
1
2
for(auto it = mtp.find(5); ******; it++)
cout <<  it->second;
И если можно, то что писать вместо звёздочек?
Или всё-таки без полного прохода по всем элементам не обойтись?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
01.05.2020, 11:48
Ответы с готовыми решениями:

Удаление записи по ключу в multimap
Доброго времени суток. Не могу разобраться с такой проблемой при удалении записи по ключу....

Доступ к элементам multimap по ключу
Подскажите, как обратиться к элементам по ключу?

Multimap. Как получить кол-во элементов по ключу?
Есть ключ. Нужно получить кол-во элементо или диапозон значений по нему.

Multimap. Ошибка operator+ not implemented in type multimap
Я начинающий в си, есть задача подсчета частоты встречаемости символов, делал через ассоциативный...

30
фрилансер
5499 / 5095 / 1047
Регистрация: 11.10.2019
Сообщений: 13,346
01.05.2020, 12:05 2
Лучший ответ Сообщение было отмечено LVV как решение

Решение

описание класса
multimap

метод equal_range

Добавлено через 2 минуты
Цитата Сообщение от LVV Посмотреть сообщение
Группируются ли в памяти элементы массива multimap по ключу
сортируются в порядке возрастания (согласно работе оператора < )
1
155 / 137 / 46
Регистрация: 15.02.2010
Сообщений: 750
01.05.2020, 12:47  [ТС] 3
Цитата Сообщение от Алексей1153 Посмотреть сообщение
сортируются в порядке возрастания
Раз элементы отсортированны по ключу, значит в памяти они расположены последовательно?
Правильно я понимаю?
А значит можно как-то применить вывод по принципу:
C++
1
2
for(auto it = mtp.find(5); ******; it++)
cout <<  it->second;
Но я не могу додуматься, какое условие поставить вместо звёздочек, чтобы остановить поиск на последнем элементе с заданным ключом.

Добавлено через 36 минут
Было бы здОрово написать что-то вместо звёздочек, чтобы заработало...
Но, вот придумал такой "костыль" и всё работает.
C++
1
2
3
int n=mtp.count(5), i=0;
for(auto it = mtp.find(5); i<n ; it++, i++)
    cout <<  it->second;
При желании и через while можно...
0
фрилансер
5499 / 5095 / 1047
Регистрация: 11.10.2019
Сообщений: 13,346
01.05.2020, 13:01 4
Лучший ответ Сообщение было отмечено LVV как решение

Решение

Цитата Сообщение от LVV Посмотреть сообщение
значит в памяти они расположены последовательно
в памяти - нет, структуру дерева можно глянуть тут

а вот итератором по ним пробежаться можно последовательно

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <map>
 
int main()
{
    std::multimap<int,int> mtp;
    
    //бежим по по всем элементам
    //it здесь - итератор
    for(auto it=mtp.begin(); it!=mtp.end(); it++)
    {
        it->first;//ключ
        it->second;//значение
    }
 
    //бежим по всем элементам (краткая запись)
    //it здесь - ссылка на элемент
    for(auto& it:mtp)
    {
        it.first;//ключ
        it.second;//значение
    }
 
    //бежим по ключу 5    
    auto r5=mtp.equal_range(5);
    //it здесь - итератор
    for(auto it=r5.first; it!=r5.second; it++)
    {
        it->first;//ключ
        it->second;//значение
    }
 
    return 0;
}
1
155 / 137 / 46
Регистрация: 15.02.2010
Сообщений: 750
01.05.2020, 13:08  [ТС] 5
Спасибо, Алексей1153, нижний пример - как раз то, что я искал.
0
Вездепух
Эксперт CЭксперт С++
11696 / 6375 / 1724
Регистрация: 18.10.2014
Сообщений: 16,070
01.05.2020, 17:08 6
Цитата Сообщение от LVV Посмотреть сообщение
нижний пример - как раз то, что я искал
Если ваша задача все равно состоит в том, чтобы пробежаться по всем элементам диапазона, то есть линейный просмотр всех элементов вы будете делать в любом случае, то более разумным может оказаться вариант
с lower_bound для поиска начала диапазона, а затем - просто ручная проверка ключей, для распознания его конца

C++
1
2
3
4
5
auto it = mtp.lower_bound(5);
for (; it != mtp.end() && it->first == 5; ++it)
{
  ...
}
Какой вариант предпочтительнее - сразу узнать конец диапазона через equal_range или найти только начало через lower_bound - трудно сказать сразу, но для таких тривиально сравниваемых ключей как int выгоднее может быть именно вариант с lower_bound, ибо equal_range выполняет двойной поиск.
1
155 / 137 / 46
Регистрация: 15.02.2010
Сообщений: 750
01.05.2020, 18:03  [ТС] 7
TheCalligrapher, задача в том, чтобы пробежаться по всем элементам с заданным ключом.
0
Вездепух
Эксперт CЭксперт С++
11696 / 6375 / 1724
Регистрация: 18.10.2014
Сообщений: 16,070
01.05.2020, 18:18 8
Цитата Сообщение от LVV Посмотреть сообщение
задача в том, чтобы пробежаться по всем элементам с заданным ключом.
О том и речь. "Элементы с заданным ключом" всегда образуют компактный диапазон в multimap. Для "пробегания" вам нужно знать начало этого диапазона.

А вот как определять конец этого диапазона - заранее через equal_range или самостоятельно путем проверки ключей в процессе "пробегания" - это уже вопрос отдельный. В вашем примере, возможно, лучше именно самостоятельно.
1
155 / 137 / 46
Регистрация: 15.02.2010
Сообщений: 750
01.05.2020, 19:05  [ТС] 9
Ну, так я уже нашел рабочее решение:
C++
1
2
3
4
int n=mtp.count(5), //определяем количество пар с заданным ключом (ключ: 5)
i=0;//счетчик
for(auto it = mtp.find(5); i<n ; it++, i++)//определяем начало диапазона и пробегаемся по нему
    cout <<  it->second;
Проверил, всё работает как надо.

Ваш вариант, хоть и посимпатичнее будет, но Вы находите положение первого элемента не по ключу, а по его значению: mtp.lower_bound(5);
Чтобы найти положение элемента с заданным ключом, нужно так: mtp.find(5);
Вот так будет то, что мне и нужно было:
C++
1
2
3
4
for (auto it = mtp.find(5); it != mtp.end() && it->first == 5; ++it)
{
  ...
}
Спасибо. Получилось неплохо.
0
Вездепух
Эксперт CЭксперт С++
11696 / 6375 / 1724
Регистрация: 18.10.2014
Сообщений: 16,070
01.05.2020, 19:10 10
Цитата Сообщение от LVV Посмотреть сообщение
Ну, так я уже нашел рабочее решение:
C++
1
2
3
4
int n=mtp.count(5), //определяем количество пар с заданным ключом (ключ: 5)
i=0;//счетчик
for(auto it = mtp.find(5); i<n ; it++, i++)//определяем начало диапазона и пробегаемся по нему
    cout <<  it->second;
Проверил, всё работает как надо.
"Работать", то оно "работает", но это уже попахивает профанацией. Вы делаете двойной пробег по требуемым элементам: сначала внутри count, затем еще раз, уже своим циклом.

Зачем тратить усилия на двойной проход по диапазону, когда достаточно одного?

Цитата Сообщение от LVV Посмотреть сообщение
Ваш вариант, хоть и посимпатичнее будет:
C++
1
2
3
4
5
auto it = mtp.lower_bound(5);
for (; it != mtp.end() && it->first == 5; ++it)
{
  ...
}
его ведь можно и так представить:
C++
1
2
3
4
for (auto it = mtp.lower_bound(5); it != mtp.end() && it->first == 5; ++it)
{
  ...
}
Да, можно и так. Это косметика.

Цитата Сообщение от LVV Посмотреть сообщение
Но вы находите положение первого элемента не по ключу, а по его значению: mtp.lower_bound(5);
Не понял. "По ключу" или "по значению ключа" - где вы тут увидели разницу?

Цитата Сообщение от LVV Посмотреть сообщение
Чтобы найти положение элемента с заданным ключом, нужно так: mtp.find(5);
Вы несете чепуху. Методы lower_bound и find - совершенно одинаковы во всем, кроме поведения, когда ключ отсутствует в контейнере вообще.

Цитата Сообщение от LVV Посмотреть сообщение
А здесь for (; it != mtp.end() && it->first == 5; ++it) Вы пробегаете до конца всего массива mtp.end(), отыскивая нужные ключи.
В обшем, не то, мне кажется
Это опять чепуха. Где вы тут увидели "пробегание до конца всего массива"? Посмотрите внимательнее на условие цикла.
0
155 / 137 / 46
Регистрация: 15.02.2010
Сообщений: 750
01.05.2020, 19:12  [ТС] 11
Извините.
Я отредактировал сообщение.
Там действитьельно говорил чепуху.
0
28 / 35 / 11
Регистрация: 11.06.2018
Сообщений: 145
01.05.2020, 19:13 12
Цитата Сообщение от LVV Посмотреть сообщение
Вы находите положение первого элемента не по ключу, а по его значению: mtp.lower_bound(5);
Чтобы найти положение элемента с заданным ключом, нужно так: mtp.find(5);
0
155 / 137 / 46
Регистрация: 15.02.2010
Сообщений: 750
01.05.2020, 19:20  [ТС] 13
На счет "по ключу" и "по значению" я, имел ввиду - по значению элемента массива multimap, ведь у него два значения: "ключ" и "собственно значение(я)", соответствующее ключу.
Ну, может в терминологии хромаю...
Разве lower_bound не по значению находит итератор?

Добавлено через 53 секунды
Тогда встречный вопрос, а как найти итератор по значению (а не по ключу) элемента массива mvultimap?
0
Вездепух
Эксперт CЭксперт С++
11696 / 6375 / 1724
Регистрация: 18.10.2014
Сообщений: 16,070
01.05.2020, 19:24 14
Цитата Сообщение от LVV Посмотреть сообщение
Разве lower_bound не по значению находит итератор?
Все поисковые методы контейнеров работают только по ключу.

Цитата Сообщение от LVV Посмотреть сообщение
Тогда встречный вопрос, а как найти итератор по значению (а не по ключу) элемента массива mvultimap?
Что такое "значение"? "Данные"? Только "вручную", путем полного просмотра. Например алгоритмом std::find_if.
1
155 / 137 / 46
Регистрация: 15.02.2010
Сообщений: 750
01.05.2020, 19:31  [ТС] 15
Понял TheCalligrapher, спасибо.
Поясните еще одно. В чем различие между find и lower_bound?
Что эффективнее для больших массивов?
lower_bound, кажется, находит положение не по конкретному ключу, а "вблизи".
То-есть, если ключи 2,3,8, то mtp.find(5) ничего не найдёт, а mtp.lower_bound(5) укажет на 3.
Или опять бред несу?

Добавлено через 1 минуту
Хотя нет, написано "большее либо равное", то есть lower_bound укажет на 8
0
фрилансер
5499 / 5095 / 1047
Регистрация: 11.10.2019
Сообщений: 13,346
01.05.2020, 20:06 16
Лучший ответ Сообщение было отмечено LVV как решение

Решение

LVV, find вернёт либо итератор на найденный первый ключ, либо end()

lower_bound вернёт итератор на первый ключ в случае, если такие ключи вообще есть. Если ключей нет, он вернёт итератор на место, куда искомый ключ можно вставить, не нарушив при этом сортировку.

То есть, в пАре lower_bound и upper_bound найдут, образно выражаясь, "локальные" begin и end этого ключа

вот аналогичный пример на отсортированном векторе (на нём индексы удобнее отобразить)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <algorithm>
#include <vector>
#include <iostream>
int main()
{
    {
        //               i== 0 1 2 3 4 5 6 7 8 9 a b
        std::vector<int> vec{3,3,4,4,5,5,5,6,6,7,8,9};
        //                           b     e
        
        //имитируем принудительную сортировку мапы
        std::sort(vec.begin(),vec.end());
        
        auto b=std::lower_bound(vec.begin(),vec.end(),5);
        auto e=std::upper_bound(vec.begin(),vec.end(),5);
        std::cout<<"b="<<*b<<" e="<<*e<<'\n';
        std::cout<<"i="<<b-vec.begin()<<" i="<<e-vec.begin()<<'\n';
    }
 
    std::cout<<"-------\n";
 
    {
        //               i== 0 1 2 3 4 5 6 7 8
        std::vector<int> vec{3,3,4,4,6,6,7,8,9};
        //                           b
        //                           e
 
        //имитируем принудительную сортировку мапы
        std::sort(vec.begin(),vec.end());
 
        auto b=std::lower_bound(vec.begin(),vec.end(),5);
        auto e=std::upper_bound(vec.begin(),vec.end(),5);
        std::cout<<"b="<<*b<<" e="<<*e<<'\n';
        std::cout<<"i="<<b-vec.begin()<<" i="<<e-vec.begin()<<'\n';
    }
 
    return 0;
}
b=5 e=6
i=4 i=7
-------
b=6 e=6
i=4 i=4
1
155 / 137 / 46
Регистрация: 15.02.2010
Сообщений: 750
01.05.2020, 20:57  [ТС] 17
Тоесть, Алексей1153, чтобы пройтись по указанном ключу -5 контейнера multimap<int,int> mtp, нужно сделать так?
C++
1
2
3
4
for (auto it = mtp.lower_bound(5); it != mtp.upper_bound(5); it++)
{
...
}
Правильно я понял?
0
фрилансер
5499 / 5095 / 1047
Регистрация: 11.10.2019
Сообщений: 13,346
01.05.2020, 21:05 18
Цитата Сообщение от LVV Посмотреть сообщение
it != mtp.upper_bound(5)
логически - да, но это не рационально в плане быстродействия. Не нужно искать upper_bound каждую итерацию, достаточно просто проверять невыход за нужный ключ

C++
1
2
3
4
5
const int key=5;
for (auto it = mtp.lower_bound(key); it != mtp.end() && it->first ==key; it++)
{
...
}
https://www.cyberforum.ru/post14494912.html
1
155 / 137 / 46
Регистрация: 15.02.2010
Сообщений: 750
13.05.2020, 13:04  [ТС] 19
Цитата Сообщение от Алексей1153 Посмотреть сообщение
const int key=5;
for (auto it = mtp.lower_bound(key); it != mtp.end() && it->first ==key; it++)
{
...
}
Ну, тогда вот так будет быстрее (вместо проверки двух условий в заголовке цикла присутствует одно условие)
C++
1
2
3
4
5
6
const int key=5;
auto itt = mtp.upper_bound(key)
for (auto it = mtp.lower_bound(key); it != itt; it++)
{
...
}
Или я не прав?
0
фрилансер
5499 / 5095 / 1047
Регистрация: 11.10.2019
Сообщений: 13,346
13.05.2020, 14:39 20
LVV, mtp.upper_bound(key) - дополнительная тяжёлая операция поиска. А сравнение it->first ==key - это пара тактов ЦП (так же, как иit != itt )
То есть, у тебя то же самое плюс дополнительный upper_bound

Но ко всему сказанному следует добавить, что все эти детали можно заранее так тщательно не выцеплять. Если во время тестирования нет тормозов, то можно оставить как есть.
А вот если есть заметные тормоза, то тогда следует начинать искать тараканов. Но перед этим следует сделать профилирование, чтобы точно определить узкое место. А то начнёшь тратить время на оптимизацию того, что на скорость и не влияет
1
13.05.2020, 14:39
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
13.05.2020, 14:39
Помогаю со студенческими работами здесь

Сгруппировать элементы указанного массива по ключу и вернуть multimap ключей
Помогите плиз, сгруппировать элементы указанного массива по ключу и вернуть multimap ключей,...

MyDictionary: сортировка по ключу, поиск значения по ключу, поиск ключа по значению
Задан интерфейс ІMyDictionary. Его реализует класс MyDictionary, который позволяет определить...

MultiMap
Всем привет.Пишу что-то на подобие MultiMap. И все бы хорошо, но тут встал вопрос об итераторах....

multimap
Я что-то не понимаю в чем проблема! #include &lt;iostream&gt; #include &lt;string&gt; #include &lt;map&gt; ...

сортировка в multimap
доброго времени суток. собственно, вопрос такой: есть программа использующая контейнер класса...

Multimap зацикливается
Всем добрый вечер, Помогите, пожалуйста разобраться с зацикленным &quot;Not found&quot;. Поиск по названию...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru