合并没有额外内存的向量

时间:2016-04-01 05:49:37

标签: c++ c++11 vector stl

我遇到了这个代码段,其中合并了两个向量,其中一个向量的元素在重复的情况下是有利的:

std::vector<String> fields1 = fieldSource1.get();
std::vector<String> fields2 = fieldSource2.get();
// original
fields1.insert(std::end(fields1), std::begin(fields2), std::end(fields2));
std::stable_sort(std::begin(fields1), std::end(fields1));
fields1.erase(std::unique(std::begin(fields1), std::end(fields1)), std::end(fields1));
return fields1;

鉴于字符串在各自的向量中是唯一的,并且输出向量中字符串的顺序是无关紧要的,我认为我可以使这个算法更有效。

我想避免额外的内存分配std :: set_union()和std :: set_diff()。

(由于在调整大小期间迭代器失效,直接将std :: set_diff插入原始向量不是一个选项)

我最终得到了这个,这是std :: set_diff,其中一个迭代器替换为索引:

std::sort(std::begin(fields1), std::end(fields1));
std::sort(std::begin(fields2), std::end(fields2));
// Initialize iterators by index in case of resizing
size_t index = 0;
size_t end = std::size(fields1);
std::remove_copy_if(std::begin(fields2), std::end(fields2), std::back_inserter(fields1),
[&fields1, &index, end](String field)->bool{
    auto begin = std::begin(fields1);
    found = std::lower_bound(begin+index, begin+end, field);
    index = std::distance(begin, found);
    return (*found) == field;
});
return fields1;

我的问题是:我可以更有效地进行此合并操作吗?如果没有,我可以让它更具可读性吗?

1 个答案:

答案 0 :(得分:0)

如果要将字符串保持为已排序或可合并状态,则将一串字符串表示为向量是低效的。最好使用另一个容器,例如std :: set或std :: unordered_set,它具有更好的性能保证。

请注意,任何尝试对字符串进行排序的解决方案都可能会进一步破坏内存,并且比首先创建正确的数据结构更多地增加内存压力。

如果必须将它们保存为字符串向量,那么您可以考虑创建一个哈希表,其中包含在每个点上看到的所有字符串,然后只允许插入其哈希值尚未被看到的字符串。如果你有大量的重复项,这种方法可能比独立排序每个列表更有效。

typedef std::size_t hash_type;
typedef std::string value_type;
typedef std::vector< value_type > values_type;
typedef std::hash< value_type > value_hash_type;
typedef std::unordered_set< hash_type > hash_set_type;

bool is_new_hash(hash_set_type &hash_set,
    const hash_type one_hash
    )
{
    if (hash_set.find(one_hash) == hash_set.end())
    {
        hash_set.insert(one_hash);
        return true;
    }
    return false;
}

int main()
{
    values_type str1, str2, dest;
    str1.push_back("c");
    str1.push_back("a");
    str1.push_back("b");

    str2.push_back("c");
    str2.push_back("d");

    hash_set_type hash_set;
    value_hash_type value_hash;

    for (auto &s : str1)
    {
        if (is_new_hash( hash_set, value_hash( s ) ))
            dest.push_back(s);
    }
    for (auto &s : str2)
    {
        if (is_new_hash(hash_set, value_hash(s)))
            dest.push_back(s);
    }
    std::sort(dest.begin(), dest.end());
}