Поиск в массиве по компоненту значения (сложный тип)

207
31 декабря 2018, 01:10

На ночь глядя голова не варит уже. Подскажите как решить следующую проблему самым эффективным (быстрым) способом на C++11, C++14, в общем не на старье :)

Итак:

typedef std::pair<int, int> data_pr;
typedef std::vector<data_pr> data_t;

как правильно получить итератор на значение:

data_t mydata;
data_t::iterator it = std::find(mydata.begin(), mydata.end(), value);

И необходимо, чтобы поиск выполнялся по функции у которой входные параметры - элемент вектора data_t, т.е. data_pr и value

И дальше проверить просто:

if (element.first == value)

Или быстрее всего будет самому в лоб делать перебор?

Answer 1

Если вектор не отсортирован, то вряд ли получится найти нужный элемент быстрее, чем за O(n) с помощью линейного поиска.

Поскольку проверку выполняет некий алгоритм, а не обычное сравнение, то стоит использовать std::find_if:

Лямбда

data_t mydata;
int value = 0;
data_t::iterator it = 
    std::find_if(
        mydata.begin(),
        mydata.end(),
        [value](const data_pr& elem) { return elem.first == value; }
    );

Функциональный объект

class data_pr_Comparer {
private:
    int _value;
public:
    data_pr_Comparer(int value) : _value(value) {}
    bool operator()(const data_pr& elem) const {
        return elem.first == _value;
    }
};
void foobar() {
    data_t mydata;
    int value = 0;
    data_t::iterator it = 
        std::find_if(
            mydata.begin(),
            mydata.end(),
            data_pr_Comparer(value)
        );
}

В целом оба этих подхода имеют право на жизнь, но функциональные объекты предоставляют дополнительные возможности - сохранение состояния между вызовами, например. Но, поскольку ваш пример не требует каких-то особых условий - используйте лямбду.

Answer 2

В дополнении к предыдущему ответу:

Если задача позволяет, то я бы сохранил std::unordered_map<int, int> вместо того, чтобы хранить вектор пар. Тогда проще получать результат, и время выполнения короче.

std::unordered_map<int, int>::const_iterator
check_1(const  std::unordered_map<int, int>& m, const int value)
{
    return m.find(value);
}

Ну а для варианта вектора пар(как у вас), существуют масса способов(не только варианты с предыдущим ответом). Например, можно определить шаблонные функции(как вы и просили, определяем возвращающие итератор функции)

using data_pr = std::pair<int, int>;
using data_t = std::vector<data_pr>;
// предикат для проверки
template <int value>
bool
Pred(const data_pr& pr)
{
    return pr.first == value;
}
//сама проверка
template<int value>
data_t::const_iterator
check_2(const data_t& v)
{
    return std::find_if(v.begin(), v.end(), Pred<value>);
}

Может иметь место и вариант без использования альгоритмов:

vector<std::pair<int, int> >::const_iterator
check_3(const vector<std::pair<int, int> > &v, const int value)
{
    auto It = v.begin();
    while (It->first != value)
            ++It;
    return It;
}

И т.д.

Answer 3

поскольку у меня в задаче сжиралась вся память (16ГБ), то нашел более оптимальный способ (опять же для моей задачи):

делал 2 прохода по всем данным, создав таблицу, где data_pr.first служило как индекс в таблицу на 8ГБ - таблица для значений в диапазоне 0x00000000 - 0x7FFFFFFF и затем таблица в диапазоне 0x80000000 - 0xFFFFFFFF

если требуется для такой таблицы больше памяти (хранится не 32 битное число, а выше), то диапазон сужается

В итоге работало быстро и памяти хватило

READ ALSO
Ширина и высота полей ввода в зависимости от содержимого

Ширина и высота полей ввода в зависимости от содержимого

Нужно задавать высоту QTextEdit в зависимости от кол-ва строк содержимого и если строк нет, то и высота нулеваяТоже самое и для QLineEdit, но для ширины

238
Имена файлов с исходным кодом в C/C++

Имена файлов с исходным кодом в C/C++

Имеются ли какие-нибудь ограничения для имени source-файла в C/C++? (в Java, например, имя source-файла должно совпадать с именем класса в нем)

214
Почему вызывается исключение в stdio_common_vfscanf?

Почему вызывается исключение в stdio_common_vfscanf?

При попытке ввода данных в scanf_s столкнулся с проблемой, которую вызывает исключение в файле stdioh

246
TomCat maven после install не запускает страницу

TomCat maven после install не запускает страницу

Помогите ничего не получаетсяВсе перепробовал, не пойму где ошибка

247