合并对象的有效方法

时间:2015-09-14 23:11:50

标签: c++ vector merge

我有一个很大的"站点列表,"说350,000左右。这些站来自五个不同的来源,每个都有特定的信息。例如,它们每个都具有五种不同类型的标识符中的至少一种。目标是合并相等的站点(如果站点具有匹配的标识符,则站点相等)。

示例:如果stationA具有identifierA:01234,identifierB:NULL和identifierC:KAKW,并且stationB具有identiferA:NULL,identifierB:USA00012和identifierC:KAKW,我想将它们合并为具有identifierA的新站点:01234 ,identifierB:USA00012,和identifierC:KAKW。

现在我将所有电台都放在一个大矢量中。我一次将一个站点移动到新的vectior中1)如果它不匹配向量中已经存在的任何站点则将其推回,或者2)如果匹配则合并它。

这花费了太多时间。从理论上讲,我可以使用一种有效的算法或概念来加速这个过程吗?我最后一次这样做了将近3天。

3 个答案:

答案 0 :(得分:0)

创建3份数据副本,每份副本按不同的标识符排序。

然后选择一个,迭代,并在已排序的容器中查找匹配项。构建组合对象并将其保存到"已处理的"矢量。

答案 1 :(得分:0)

似乎它应该是一个哈希表-y类型的问题,但也许它不是,因为两个站点的方法不止一种

如果你能省下记忆,我会建议类似阿米特的回答。只需要5个std::map个标识符容器作为主容器(如数据库)的索引,然后以这种方式进行搜索。有一些前期工作将标识符放入已排序的容器中,但最终可能会更快。

如果您不关心哪个标识符匹配哪个,或者您的标识符数据集不相交,您可以使用一个容器,其中所有五个标识符一起排列(可能是哈希值,但不包括NULL,大概),并搜索。

答案 2 :(得分:0)

下面的代码会对站点进行传递,从而有效地生成站点所具有的标识符的位掩码。它翻转这些位以创建一个位掩码,只有缺少标识符的另一个站将具有该位掩码,并且如果已知这样的站与它合并,则将合并的站添加到稍后要擦除的列表中。否则,它会将不匹配的工作站添加到具有特定位掩码的工作站列表中,以便以后可以快速找到它。 (很少进行测试。)

#include <iostream>
#include <string>
#include <vector>

struct Station
{
    int idn_map() const { return 16 * bool(ia_[0]) +
                                  8 * bool(ib_[0]) +
                                  4 * bool(ic_[0]) +
                                  2 * bool(id_[0]) +
                                      bool(ie_[0]); }
    void merge(const Station& rhs)
    {
        if (ia_.empty()) ia_ = rhs.ia_;
        if (ib_.empty()) ib_ = rhs.ib_;
        if (ic_.empty()) ic_ = rhs.ic_;
        if (id_.empty()) id_ = rhs.id_;
        if (ie_.empty()) ie_ = rhs.ie_;
    }

    std::string ia_, ib_, ic_, id_, ie_;
};

std::ostream& operator<<(std::ostream& os, const Station& s)
{
    return os << s.ia_ << ':' << s.ib_ << ':' << s.ic_ << ':' << s.id_ << ':' << s.ie_;
}

int main()
{
    std::vector<Station> stations = {
        { "s0a", "",    "s0c", "",    "s0e" },
        { "",    "",    "s1c", "s1d", "s1e" },
        { "",    "s2b", "",    "s2d", "" },
        { "s3a", "s3b", "s3c", "s3d", "" },
        { "s4a", "s4b", "",    "",    "" }
    };

    std::vector<Station*> unmatched[32];
    std::vector<Station*> to_erase;
    for (Station& s : stations)
    {
        int idn_map = s.idn_map();
        if (unmatched[idn_map ^ 31].empty())
            unmatched[idn_map].push_back(&s);
        else
        {
            // merge from current element so to_erase kept sorted
            // for fast compact/erase later...
            Station* p_merge_to = unmatched[idn_map ^ 31].back();
            p_merge_to->merge(s);
            to_erase.push_back(&s);
            unmatched[idn_map ^ 31].pop_back();
        }
    }
    for (const auto& p : to_erase)
        std::cout << "will remove element at " << p << '\n';
    // now compact over the deferred erasures...
    auto erase_it = to_erase.begin();
    auto to = stations.begin();
    for (auto from = to; from != stations.end(); ++from)
        if (erase_it != to_erase.end() && *erase_it == &*from)
            ++erase_it;
        else
            *to++ = *from;
    stations.erase(to, stations.end());

    std::cout << "results:\n";
    for (const auto& station : stations)
        std::cout << station << '\n'; 
}

代码可用/可运行here

(在我修正循环逻辑时进行了几次编辑,从使用集合更改为向量以提高性能)

相关问题