2011-01-02 2 views
1

Можете ли вы написать перегруженную функцию, чтобы удалить объект DATA из набора, например: s.erase(4) Здесь 4 может быть значением или x или y.Набор типа класса

struct DATA 
{ 
    DATA(int X, int Y):x(X), y(Y){} 
    int x; 
    int y; 

    bool operator < (const DATA &d) const 
    { 
     return x < d.x || (x == d.x && y < d.y); 
    } 
}; 


int main() 
{ 
    set <DATA> s; 

    for (int i = 0; i < 5; i++) 
     s.insert(DATA(i, i+5)); 

    s.erase(0) // remove where x = 0 
} 
+0

Не можете ли вы просто перегрузить «operator ==»? – dutt

ответ

0

Нет; ваш набор упорядочен по X, вы также не можете заказать набор по Y, чтобы удалить его. Вам нужно будет выполнить итерацию по набору, чтобы найти элементы, которые вы хотите удалить, а затем удалить их, как вы обычно удаляете из набора.

+0

Нет, его набор упорядочен по 'x' * и *' y'. См. Его функцию компаратора. –

+0

(Действительно, «проблема» заключается в том, что он не может выборочно индексировать один или другой, они неразрывно связаны как пара значений.) –

+0

@Tomalak: y является вторичным ключом - набор индексируется по x и y используется для разрыва связей. Вы можете найти первичный ключ (x), но вы не можете искать вторичный (по крайней мере, не с одной установленной структурой). –

2

Несомненно!

Вы можете написать функтор для поиска элементов набора, где EITHER x или y равно 4, и стирать такие элементы. Вы хотите, чтобы сделать boost::bind связывание проще:

#include <set> 
#include <algorithm> 
#include <boost/bind.hpp> 

struct Foo { 
    int x, y; 

    bool operator<(const Foo& rhs) const { 
     return (x < rhs.x || (x == rhs.x && y < rhs.y)); 
    } 

    bool hasValue(int v) const { 
     return (x == v || y == v); 
    } 
}; 

int main() 
{ 
    std::set<Foo> s; 
    Foo a = {4,2}; s.insert(a); 
    Foo b = {3,4}; s.insert(b); 

    std::cout << s.size() << std::endl; // will output: "2" 

    std::set<Foo>::iterator it; 

    // Search for an element with the given value '4' in either x or y 
    // Erase first matching element found, if any 
    // (our first element, which has x=4) 
    it = std::find_if(s.begin(), s.end(), boost::bind(&Foo::hasValue, _1, 4)); 
    if (it != s.end()) 
     s.erase(it); 

    std::cout << s.size() << std::endl; // will output: "1" 

    // Erase the next one 
    // (our second element, which has y=4) 
    it = std::find_if(s.begin(), s.end(), boost::bind(&Foo::hasValue, _1, 4)); 
    if (it != s.end()) 
     s.erase(it); 

    std::cout << s.size() << std::endl; // will output: "0" 
} 

Не был протестирован на опечатки.

Вы можете получить ту же функциональность без boost, используя статическую функцию-член, которая принимает Foo* в качестве аргумента.

+0

Да, вы могли бы перебирать все это, но вы не получаете характеристики производительности набора (ваш поиск и удаление занимает O (n^2 lg n), тогда как требуется, чтобы набор принимал O (lg n) времени). Еще лучше использовать рукописный цикл, который содержит теги всех элементов, которые вы хотите удалить, и удалите их все сразу (как указано в моем ответе), который уменьшает общее время до O (n lg n). –

+0

Предварительная итерация была бы хорошей оптимизацией, да. –

+0

Что касается потери характеристик производительности набора, это присуще требованию OP.Честно говоря, ИМО, желая сделать это, в первую очередь, немного запах кода. –

0

Sure- вы можете изменить структуру данных, чтобы работать с более крупным интегральным типом и использовать бит-сдвиг, чтобы упаковать пару меньших интегральных типов. Однако в более общем смысле, то нет. Существуют контейнеры с несколькими индексами, но std :: set не является одним из них.

+0

Я не уверен, как слияние с более крупным интегральным типом поможет найти частичное значение в std :: set. В любом случае, даже если бы это было возможно, я не думаю, что вы должны дать новичкам идеи о том, как обфускать их код в забвение ... :) – villintehaspam

0

Как насчет std::map контейнера? Вы можете либо использовать x, либо y как key_type и сохранить значения не-ключа в классе как value_type.

+1

Или 'boost :: bimap' использовать любое значение как ключ при каждом выборе. –

Смежные вопросы