2

我有一个std::set并且我需要删除相似的相邻元素:

DnaSet::const_iterator next = dna_list.begin();
DnaSet::const_iterator actual = next;
++next;

while(next != dna_list.end()) // cycle over pairs, dna_list is the set
{
    if (similar(*actual, *next))
    {
        Dna dna_temp(*actual);  // copy constructor
        dna_list.erase(actual); // erase the old one
        do
        {
           dna_temp.mutate(); // change dna_temp
        } while(!dna_list.insert(dna_temp).second);  // insert dna_temp
    }
    ++actual;
    ++next;
}

有时程序无法退出主循环。我认为当我删除dna_list. 执行此任务的正确方法是什么?

4

2 回答 2

5

使用actual = next而不是++actual.

一旦你擦除actual,它就是一个无效的迭代器,所以++actual会表现得很奇怪。next应该保持不变,所以分配actual应该next工作。

于 2010-07-28T23:26:52.473 回答
2

您最好的选择是创建一个使用similar()谓词的比较函子。然后你需要做的就是用那个比较函子构造集合,你就完成了。集合本身会将两个相似的元素视为相同,并且只会让第一个元素进入。

struct lt_different {
    bool operator()(int a, int b) {
        return a < b && !similar(a, b);
    }

private:
    bool similar(int a, int b)
    {
        // TODO:when are two elements similar?
        const int EPSILON = 2;
        return abs(a - b) < EPSILON;
    }
};

// ...
set<int> o;  // fill this set with your data

// copy your data to a new set that rejects similar elements
set<int,lt_different> s(o.begin(), o.end(), lt_different());

您可以使用 set s:插入元素、删除元素、修改元素——并且集合本身将确保集合中不存在两个相似的元素。

也就是说,您也可以自己编写算法,如果只是为了另一种选择。看看std::adjacent_find()<algorithm>。它将找到两个连续相同元素的第一次出现;坚持那个位置。找到之后,从该点找到与这些元素不同的第一个元素。您最终会得到两个迭代器,它们表示一系列连续的相似元素。您可以使用 set 的erase()方法来删除它们,因为它有一个需要两个迭代器的重载。

起泡,冲洗,整套重复。

于 2010-07-28T23:28:08.413 回答