使用不同的比较函数合并两个已排序的双向量

时间:2018-01-11 14:10:27

标签: c++ vector merge stl numeric

我有两个已排序的std::vector<double>个容器。现在我需要将两个向量合并到一个新的已排序容器中,并带有限制, 当且仅当std::fabs(a-b)<1.e-6成立时,才应认为这两个值相等。这个问题在我们的网站中出现了很多次 代码和我正在寻找最好的解决方案。

我的第一次尝试是:

std::vector<double> mergeTimeLists(const std::vector<double>& sorted1, const std::vector<double>& sorted2) {    
    auto cmp = [&](double a, double b)->bool { return std::fabs(a - b) > 1e-6 && a < b; };
    std::set<double, decltype(cmp)> set(cmp);
    std::copy(sorted1.begin(), sorted1.end(), std::inserter(set, set.begin()));
    std::copy(sorted2.begin(), sorted2.end(), std::inserter(set, set.begin()));
    std::vector<double> ret;
    std::copy(set.begin(), set.end(), std::back_inserter(ret));
    return ret;
}

在再次咨询STL的文档后,我提出了:

std::vector<double> mergeTimeLists1(const std::vector<double>& sorted1, const std::vector<double>& sorted2) {
    std::vector<double> ret;
    std::merge(sorted1.begin(), sorted1.end(), sorted2.begin(), sorted2.end(), std::back_inserter(ret));
    ret.erase(std::unique(ret.begin(), ret.end(), [&](double a, double b)->bool { return std::fabs(a - b) < 1e-6; }),ret.end());
    return ret;
}

这是我的测试:

int main(int argc, char** args) {
    {
        auto ret = mergeTimeLists({ 0,0.1,0.2,0.3,0.34 }, { 0.05,0.10000001 });
        std::copy(ret.begin(), ret.end(), std::ostream_iterator<double>(std::cout, " "));
    }
    std::cout << std::endl;
    {
        auto ret = mergeTimeLists1({ 0,0.1,0.2,0.3,0.34 }, { 0.05,0.10000001 });
        std::copy(ret.begin(), ret.end(), std::ostream_iterator<double>(std::cout, " "));
    }

}

有没有人有改进的想法?

修订问题

看来,我无法完全清楚明确地陈述我的问题。事实证明,我真正想要的是略有不同。

假设我有两个已排序的std::vector<double>容器s1s2。我想创建一个新的排序容器s,其中包含s1中的所有值和s2中的一些值,而来自v的值s2仅包含在s当且仅当u中没有值s1时,std::fabs(u-v)<1e-6

因此,如果s2中的某些值不太接近,我只希望s的值位于结果容器s1中。

我很抱歉没有事先说清楚我的问题,而且我对目前已经得到的反馈感到非常高兴。也许我还能从这里得到什么想法?

1 个答案:

答案 0 :(得分:1)

对矢量进行排序。结果也是一个有序的向量。

使用std::merge()是一个良好的开端,但您的示例在两个方面达不到最佳效果:

  1. 在合并之前,您忽略了在返回的向量中保留容量。
  2. 您在合并期间插入所有元素,然后在其后删除不需要的元素。
  3. 第一个问题很简单:

    ret.reserve(std::max(sorted1.size(), sorted2.size()));
    

    第二个可以通过改变给std::merge()的输出迭代器来解决。而不是std::back_inserter(ret),而是创建自己的unique_inserter(ret),如下所示:

    struct unique_inserter
        : std::back_insert_iterator<std::vector<double>>
    {
        typedef std::back_insert_iterator<std::vector<double>> base;
    
        unique_inserter(std::vector<double>& out) : base(out) {}
    
        unique_inserter& operator=(const double& value)
        {
            if (container->empty() || std::fabs(container->back() - value) > 1e-6)
                container->push_back(value);
            return *this;
        }
    
        // remove this if not using C++11
        unique_inserter& operator=(const double&& value)
        {
            if (container->empty() || std::fabs(container->back() - value) > 1e-6)
                container->push_back(std::move(value));
            return *this;
        }
    };
    

    这与std::back_inserter类似,但如果新值等同于最后一个值,则不执行任何操作。这样,永远不会插入不需要的值,也不需要在以后擦除。