从两个向量中删除垂直反向重复项

时间:2016-02-20 13:20:49

标签: c++ vector

我从一个包含两列的文本文件中填充两个向量:

while (infile >> a >> b) {
    Alist.insert(Alist.end(), a);
    Blist.insert(Blist.end(), b);
}

到目前为止,这些载体包含的数字如下:

Alist Blist
1     6
1     4
2     4
2     7
2     5
2     3
3     9
3     2
3     5
4     1
4     6
5     3
5     2
5     8
5     9
6     4
6     1
7     2
8     5
8     9
9     3
9     5
9     8

我希望移除其中一对夫妻,例如1 6 6 1。我想删除6 1。还有更多情侣,例如1 4 4 1。我怎样才能做到这一点?

刚刚开始研究:

int g = 0, h =0;
for (int i = 0; i < Alist.size(); i++) {
    g = Alist[i];
    h = Blist[i];
    for (int y = 0; y < Blist.size(); y++) {
        if (Blist[y] == g && Alist[y] == h) {
            Alist.erase(Alist.begin() + y);
            Blist.erase(Blist.begin() + y);
        }
    }
}

2 个答案:

答案 0 :(得分:1)

正如其他人所建议的,一种可能的方法是使用std::map对来确保唯一性(一旦给出比较函数)。您可以在将一对添加到容器之前测试重复项,从而避免在搜索和删除之后。

#include <set>

using pair_int = std::pair<int,int>;

struct comp_pair {
    constexpr bool operator()(const pair_int &lhs, const pair_int &rhs) const {
        // compare the two pairs by their elements
        return lhs.first < rhs.first ? true : (
            lhs.first == rhs.first && lhs.second < rhs.second ? true : false);
    }
};

std::set<pair_int,comp_pair> ABlist;

while ( std::cin >> a >> b ) {
    // Assuming that A list is sorted, only pairs in which a > b can already
    // be present in the container as a (b,a) pair
    if ( a > b  &&  ABlist.find(std::make_pair(b,a)) != ABlist.end() )
        // if there is a match, go on without inserting anything
        continue;
    // insert a pair. The container grants for uniqueness
    ABlist.insert(std::make_pair(a,b));
}

这个片段在测试程序中包含您提供的输入示例,产生以下输出:

1 4
1 6
2 3
2 4
2 5
2 7
3 5
3 9
4 6
5 8
5 9
8 9

答案 1 :(得分:0)

第一项改进,基于您的初始代码

您的代码没有考虑Alist[i]==Blist[i]总是被淘汰的情况。它也会错过多个相同的对,因为它没有考虑当前位置通过擦除移动到下一个项目。在最坏的情况下,它甚至会在内循环中超出范围,因为向量会缩小。

请注意,i之前的项目的反向联系已被删除。您可以通过在当前位置之后开始搜索反转来使用它来改善您的算法:

for (int i = 0; i < Alist.size(); i++) {
    int g = Alist[i];
    int h = Blist[i];
    for (int y = i+1; y < Blist.size(); ) {  // start with next
        if (Alist[y] == h && Blist[y] == g) { 
            Alist.erase(Alist.begin() + y);
            Blist.erase(Blist.begin() + y);
        }
        else y++; // move to next only if current one was not erased
    }
}

AList已经排序的事实(根据你的评论)确保对于1 6和6 1,第二个将被淘汰:

你可以通过利用排序的Alist:当超过目标时停止内循环来进一步改善,并且只有在有机会找到某些东西时进入循环,即如果h> = = g:

   if (h>=g)
        for (int y = i+1; y < Blist.size() && Alist[y]<=h; ) {  // start with next, stop if over target
             ...
        } 

Online demo

进一步改善

您最终可以通过使用二分搜索来查找Blist[i]Alist的第一次出现。然而,保持先前修剪方法的优点,并将此ony用作内部for循环中y的起始值。

相关问题