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

Remove vertical reversed duplicates from two vectors

本文关键字:垂直 删除 向量 两个      更新时间:2023-10-16

我用两列填充文本文件中的两个向量:

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);
        }
    }
}

正如其他人所建议的,一种可能的方法是使用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

基于初始代码的首次改进

您的代码没有考虑到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
             ...
        } 

在线演示

进一步改进

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