Поиск на карте stl

У меня есть карта с указателем структуры в качестве ключа.

std :: map <struct1 *, struct2>;

struct struct1 {int x; char a [10]; }; struct struct2 {int x; };

Ключ - это указатель на struct1. структура struct1 имеет член с именем x.

Мне нужно выполнить поиск на карте по члену x структуры struct1.

Можно ли искать, не просматривая все элементы на карте?

Я пробовал код ниже, но он не работает.

include <iostream>
#include <map>
struct struct1 { int x; char a[10]; };
struct struct2{ int x; };

bool operator<(const struct1 & fk1, const struct1& fk2) { 
    return fk1.x < fk2.x;
}
int main()
{  
    std::map<struct1 *, struct2> m;
    struct1 *f1 = new struct1();
    f1->x =1;
    strcpy(f1->a,"ab");
    struct2 l1;
    l1.x=10;
    m.insert(std::make_pair(f1, l1));

    struct1 fk1;
    fk1.x=1;
    std::map<struct1 *, struct2>::iterator x = m.find(&fk1);
    if (x != m.end())
    {
        std::cout << x->first->x <<std::endl;
        std::cout << x->first->a <<std::endl;
    }


   if (f1!=NULL)
   delete f1;
return 0;
}

Это не работает, потому что указатель&fk1 отсутствует на вашей карте. Если вы хотите, чтобы поиск выполнялся с использованием того, на что указывает указатель, вместо использования самого указателя, вам понадобится настраиваемый компаратор.

john 03.12.2018 11:04

@john -как написать собственный компаратор?

user369287 03.12.2018 11:07

Ваша карта упорядочена по набору адресов в качестве ключей. Правильно ли это или нет, только вы можете сказать (не неслыханно, но это немного странно). Следовательно, нет простого поиска, если бы он не был вашим основным линейным обходом O (n). Это не похоже на то, что настраиваемый компаратор поможет. после карта уже заполнена и упорядочена чем-то совершенно другим. Если вы используете этот компаратор в качестве фактического упорядочивания карты при построении, тогда, это будет огромным подспорьем, но убедитесь, что он обеспечивает строгое слабое упорядочение по набору ключей.

WhozCraig 03.12.2018 11:11

Вы уверены, что хотите map<struct1*,struct2>, а не map<struct1,struct2>? Указатели не так полезны, как ключи

463035818_is_not_a_number 03.12.2018 12:19
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
112
3

Ответы 3

Используйте настраиваемый компаратор, чтобы передать указанные значения в уже существующий operator<. Нравится

struct Cmp
{
    // use pointed to value for comparison
    bool operator()(const struct1* x, const struct1* y) const { return *x < *y; }
};

std::map<struct1 *, struct2, Cmp> m;

Я попробовал ваше предложение. Я получаю следующие ошибки Ошибка 3 Ошибка C2679: двоичный '! =': Не найден оператор, который принимает правый операнд типа 'std :: _ Tree <_Traits> :: iterator' (или нет приемлемого преобразование) Ошибка 1 ошибка C2676: двоичный '<': 'const struct1' не определяет этот оператор или преобразование в тип, приемлемый для предопределенного оператора Ошибка 2 ошибка C2440: 'инициализация': невозможно преобразовать из 'std :: _ Tree < _Traits> :: iterator 'в' std :: _ Tree <_Traits> :: iterator '

user369287 03.12.2018 11:25

Вам нужно изменить std::map<struct1 *, struct2>::iterator на std::map<struct1 *, struct2, Cmp>::iterator, или вы можете использовать typedef для std::map<struct1 *, struct2, Cmp>, или вы можете использовать функции C++ 11 и сказать auto x = ...

john 03.12.2018 11:33

Давайте расширим параметры m по умолчанию:

std::map<struct1 *, struct2, std::less<struct1 *>, std::allocator<std::pair<const struct1 *, struct2> >

Мы видим, что компаратором карты является std::less<struct1 *>, который будет проверять числовое значение аргументов указателя. Это не звонитstruct1::operator <.

Если у вас есть компилятор C++ 14 и вы хотите искать по члену int, вы должны использовать настраиваемый компаратор, который является прозрачный, например

struct struct1_less
{
    typedef void is_transparent;
    // C++11 and later: using is_transparent = void;

    // compare pointers
    bool operator()(const struct1* lhs, const struct1* rhs) const { return lhs->x < rhs->x; }
    // compare with int
    bool operator()(const struct1* lhs, int rhs) const { return lhs->x < rhs; }
    bool operator()(int lhs, const struct1* rhs) const { return lhs < rhs->x; }
};

Используется как

typedef std::map<struct1 *, struct2, struct1_less> struct1_lookup;

int main()
{  
    struct1_lookup m;
    struct1 *f1 = new struct1();
    f1->x =1;
    strcpy(f1->a,"ab");
    struct2 l1;
    l1.x=10;
    m.insert(std::make_pair(f1, l1));

    struct1 fk1;
    fk1.x=1;
    struct1_lookup::iterator x = m.find(&fk1);
    if (x != m.end())
    {
        std::cout << x->first->x <<std::endl;
        std::cout << x->first->a <<std::endl;
    }

    delete f1;
    return 0;
}

как объявить итератор этим кодом FatKey fk1; fk1.x = 1; std :: map <FatKey *, LightKey> :: iterator it_1 = m.find (& fk1); дает мне ошибку C2679: двоичный '=': не найден оператор, который принимает правый операнд типа 'std :: _ Tree <_Traits> :: iterator' (или нет приемлемого преобразования)

user369287 03.12.2018 12:21

@ user369287 Вам необходимо сопоставить тип итератора с типом карты точный. std::map<struct1 *, struct2, struct1_less>::iterator не связан с std::map<struct1 *, struct2>::iterator. В подобных случаях полезно использовать псевдоним типа (typedef).

Caleth 03.12.2018 12:53

Вы можете использовать функцию std :: find_if, например:

int search_value = 222;

auto it = std::find_if (m.begin(), m.end(), [search_value](const pair<struct1*, struct2> &s){ return s.first->x == search_value;});

@ как изменить приведенный выше код C++ 9.0 (Visual Studio 2008)

user369287 03.12.2018 12:38

Другие вопросы по теме