更有效的向量比较

时间:2018-11-13 22:17:33

标签: c++ vector

我正在尝试比较2个不同的向量以捕获任何重复项。一个向量是10个数字中的500万个元素,另一个是10个元素中的280万个元素。 我的操作系统是ubuntu 18.04,我正在使用QtCreator。当我尝试比较这些大向量时,我遇到了麻烦。这是我尝试过的:

vector<vector<int> >::iterator v1;
vector<vector<int> >::iterator v2;

for(v1 = vector1.begin(); v1 != vector1.end(); v1++)
    {
        for(v2 = vector2.begin(); v2 != vector2.end(); v2++)
        {
            if(*v1 == *v2)
            {
                vector1.erase(v1);
            }
        }
    }

当我尝试运行它并调试Qt挂起时。我也想知道是否需要更改擦除内容:

vector1.erase(v1.begin(), v1.end());

任何有关“更好”的方式的建议都将有所帮助。我知道这些是一些大向量,其中有10个数字超过2个半百万元素。

提前谢谢

Idzireit

仍然解决问题。现在,我正在尝试Mark Ransom解决方案的派生产品。这是到目前为止我得到的:

#include "includes.h"

bool vec_less(vector<int> &v1, vector<int> &v2)
{

    for(int i = 0; i < 10; i++)
    {
        if(v1[i] == v2[i])
        {
            i++;
        }
        if(v1[i] < v2[i])
            return true;
        else
            return false;
    }
    return v1.size() <v2.size();
}

void dupfilter(vector<vector<int> > &aaperms, vector<vector<int> > &perms)
{
    vector<vector<int> >::iterator v1 = aaperms.begin();
    vector<vector<int> >::iterator v2 = perms.begin();

    while(v1 != aaperms.end() && v2 != perms.end())
    {

        if(*v1 == *v2)
        {
            aaperms.erase(v1);
            ++v1;
            ++v2;
        }

        if(vec_less(*v1, *v2) == true)
            ++v1;
        else
            ++v2;
    }

    return;
}

我只需要对1个向量进行排序。另一个按原样进行排序。 我现在用附加代码遇到的问题是找不到重复项。它确实会遍历每个向量一次,但是由于某种原因它没有找到重复项。我知道有些原因是因为尽管我遇到了严重的sigseg故障,但先前的尝试并对其进行了分类发现了它们。

我一直在努力地绕过自动和独特的领域,只是无法完全理解示例和我的(代码?方法?)相吻合。

Idzireit

2 个答案:

答案 0 :(得分:7)

您的解决方案存在两个三个问题。

  1. 您的代码具有未定义的行为。删除项目时,迭代器无效。

  2. 您的代码具有很大的复杂性 o(n^2) o(n^3)

  3. 从向量的中间删除项具有线性复杂度,因此对于大向量,应避免使用。这就是为什么我更正了2点。

下面的代码具有o(n)的时间复杂度,通常最好使用STL算法:

using Vec = std::vector<std::vector<int>>;

void removeItems(Vec& from, const Vec& itemsToRemove)
{
    const std::unordered_set<Vec::value_type> items {
       itemsToRemove.begin(),
       itemsToRemove.end()
    };

    auto it = 
    std::remove_if(from.begin(), from.end(),
                   [&items](const auto &x){
                       return items.count(x) != 0;
                   });
    from.erase(it, from.end());
}

您可以考虑将内部std::vector替换为std::array,因为正如您所描述的那样,它具有恒定的大小,这将减少内存碎片(应该提供额外的提升)。

using Vec = std::vector<std::array<int, 5>>;

答案 1 :(得分:3)

您选择的算法为O(n²),这意味着对于大型数据集,将需要很长时间。很容易看出您为什么认为它挂了。

如果您不关心排序,则可以对两个向量进行排序,以将其从O(n²)问题转换为O(n log n)。对它们进行排序后,您将同时浏览每个向量,并根据哪个小于另一个来增加索引。

如果您无法一次将整个数据集放入内存中,甚至可以通过从已排序的文件中读取来使用此方法。

bool vec_less(const vector<int>& v1, const vector<int>& v2)
{
    for (int i = 0; i < v1.size() && i < v2.size(); i++)
    {
        if (v1[i] < v2[i])
            return true;
        if (v2[i] < v1[i])
            return false;
    }
    return v1.size() < v2.size();
}

std::sort(vector1.begin(), vector1.end(), vec_less);
std::sort(vector2.begin(), vector2.end(), vec_less);
vector<vector<int> >::iterator v1 = vector1.begin();
vector<vector<int> >::iterator v1out = v1;
vector<vector<int> >::iterator v2 = vector2.begin();

while (v1 != vector1.end())
{
    if (v2 == vector2.end() || vec_less(*v1, *v2))
    {
        if (v1out != v1)
            *v1out = *v1;
        ++v1;
        ++v1out;
    }
    else if (vec_less(*v2, *v1))
        ++v2;
    else // equal
    {
        ++v1;
        ++v2;
    }
}
vector1.resize(v1out - vector1.begin());