C Контейнер структур, необходимый для операций поиска с двойным доступом

#c #search #struct #find #containers

#c #Поиск #структура #Найти #контейнеры

Вопрос:

У меня есть структура, которую мне нужно поместить в контейнер на C . вот структура:

 struct PDCUTestMessage
{
string name;
unsigned char id;
int numberOfParameters;
string param1Name;
string param2Name;
string param3Name;
string param4Name;
string param5Name;
boost::function<void(vector<unsigned char>)> process;
PDCUTestMessage();
PDCUTestMessage(string_name, unsigned char _id, int _numberOfParameters, boost::function<void(vector<unsigned char>)> _process): name(_name), id(_id), numberOfParameters(_numberOfParameters), process(_process){}
};
  

Мне понадобится около 65 таких структур, поэтому я хочу поместить их в контейнер (я думаю, список, вектор или карту). Мне нужно иметь возможность обращаться к указателю функции (процессу) данного PDCUTestMessage с помощью двух разных значений поиска: name и id. Я заметил, что map допускает только одно значение и один ключ. Есть ли какой-либо контейнер, который позволил бы мне быстро искать PDCUTestMessage, использующий имя или идентификатор в качестве ключа? И как бы я написал поиск и получил доступ к функции, на которую указывает указатель?

Я надеюсь, что это имеет смысл. Дайте мне знать, если вам нужны дополнительные разъяснения.

Спасибо!

Комментарии:

1. Если у вас есть «около 65» объектов, использование std::vector было бы неплохо.

Ответ №1:

Поскольку вы уже используете boost, здесь может пригодиться библиотека контейнеров boost.multi-index. В частности, рассмотрите примеры в разделе руководства по множественной сортировке.

Комментарии:

1. Это выглядит многообещающе. Я вроде как новичок в C , поэтому надеюсь, что смогу это понять. Есть ли другие ссылки или примеры использования мультииндексации в этом контексте?

Ответ №2:

Поскольку в вашем контейнере всего 65 элементов, простой линейный поиск может быть достаточно быстрым для ваших нужд. Используйте имя в качестве ключа для вашей карты (или набора) и используйте std::find, когда вам нужно выполнить поиск по идентификатору.

Комментарии:

1. Я мало что сделал с maps и std::find. У меня сложилось впечатление, что вы можете выполнять поиск только с помощью find, используя ключ записи map, или, по крайней мере, это примеры, которые я нахожу. Есть ли у вас какие-либо примеры того, как я мог бы сделать это с помощью map и find? Кстати, ID будет наиболее часто используемым ключом. Итак, я бы настроил это в противоположность тому, что вы сказали? С идентификатором в качестве ключа и std::find с именем?

Ответ №3:

Как уже упоминалось Boost.Мультииндекс — это один из способов решения подобной проблемы. Это очень мощный и быстрый инструмент, но в большинстве случаев это просто означает медленную компиляцию и сложный код, не получая при этом особых других преимуществ.

65 элементов — это не так уж много, и, как упоминал Марк Рэнсом, линейный поиск может работать достаточно хорошо для того, что вы делаете. Это вам нужно измерить.

Другой способ сделать что-то — иметь std:: vector, содержащий сообщения (65 сообщений), и тогда у вас могут быть два отдельных контейнера, которые вы используете для поиска: первый — id-to-index, а второй — name-to-index. Индекс — это позиция сообщения в векторе. Что-то вроде этого:

 class YourContainerClass
{
public:
    bool lookupById(unsigned char id, PDCUTestMessageamp; message)
    {
        std::map<unsigned char, int>::iterator it = idToIndexMap.find(id);
        if (it == idToIndexMap.end())
            return false;
        message = messages[*it];
        return true;
    }

    bool lookupByName(const std::stringamp; name, PDCUTestMessageamp; message)
    {
        std::map<std::string, int>::iterator it = nameToIndexMap.find(id);
        if (it == nameToIndexMap.end())
            return false;
        message = messages[*it];
        return true;
    }

private:
    std::vector<PDCUTestMessage> messages;
    std::map<unsigned char, int> idToIndexMap;
    std::map<std::string, int> nameToIndexMap;
};
  

Для управления внутренними контейнерами ваша вставка должна выполнять работу с push_back в векторе сообщений и в то же время вставлять в две карты соответствующие объекты, чтобы найти индекс в векторе по идентификатору и имени.

Это всего лишь один из способов, как будет выглядеть API. Вы также могли бы обернуть сообщения в boost::shared_ptr, чтобы получить немного другой API. Это немного выходит за рамки вашего вопроса, потому что я также не знаю, как вы собираетесь использовать сообщения и время их жизни.

Я бы сказал, даже если Boost.MultiIndex — очень классный контейнер, он не должен быть первым вариантом. Есть много способов сделать это, и это сводится к конкретным проблемам, что имеет наибольший смысл.

Надеюсь, вы найдете то, что имеет наибольший смысл для вас.