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

Merge two sorted double vectors using different comparision function

本文关键字:两个 排序 向量 合并 比较 函数      更新时间:2023-10-16

我有两个排序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中的一些值,而s2中的值v仅包含在s中当且仅当s1中没有值u时,这样std::fabs(u-v)<1e-6

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

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

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

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

  1. 您忽略了在合并之前在返回的向量中保留容量。
  2. 您可以在合并过程中插入所有元素,然后在合并后擦除不需要的元素。

第一个是微不足道的:

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但如果新值等效于最后一个值,则不执行任何操作。 这样,不需要的值永远不会插入,以后也不需要擦除。