remove_neighbors以类似STL的方式
remove_neighbors in STL like fashion
我正试图以STL的方式实现一种具有以下功能的算法:
给定一个范围[first,last)
、一个邻域跨度nSpan
和一个(二进制)谓词Pred
,它会从该范围中删除元素,因此对于最多相距nSpan
的任何剩余元素,Pred
都不成立
示例:
nSpan
=1和Pred
=Equality=>衰减到std::unique
算法-
nSpan
=2和Pred
=PointEquality=>清除多段线+ P2 | v ^ P0 | P4 P0 P1 P4 +---->-------+---->------+ becomes +---->-------+---->------+ P1 P3
nSpan
=2和Pred
=相等:[‘a','b','a','d','e','d','f']->[‘a','d','f']
在最后一个例子中,很明显(为了防止算法变得模糊),我们从第一个迭代器开始扫描,同时检查nSpan距离以删除元素(否则将有多种方法删除元素)。
到目前为止,我的尝试(下面列出的代码)有以下缺点:
- 第一次扫描后,新范围可能有无效的新元素,因此需要递归功能(再次从新开始扫描到结束)来重新扫描范围(或者每次删除时都可能启动递归)
- 它不是作为
remove
函数实现的,而是作为erase
函数实现的(我需要一个remove函数,这似乎要困难得多),这迫使我们将整个容器作为参数而不是范围来提供(理想情况下,算法应该与容器无关)
我列出了第一次尝试
template<typename Cont, typename It, class Pr>
void erase_neighbors(Cont &cont, It first, It last, int nSpan, Pr Pred)
{
if (0 < nSpan && nSpan < std::distance(first, last)) for (It it2; (it2 = first), first != last; )
{
if (nSpan < std::distance(it2, last))
{
std::advance(it2, nSpan);
if (Pred(*first, *it2))
{
first = cont.erase(first, it2);
last = cont.end();
continue;
}
}
++first;
}
}
理想签名
template<typename It, class Pr>
It remove_neighbors(It first, It last, int nSpan, Pr Pred);
理想的实现:非c++11且没有boost(即使有相关的boost算法,我也很乐意了解它)
在我理解问题陈述的范围内,这似乎符合您的要求。看看它在行动:
template<typename It, class Pr>
It remove_neighbors(It first, It last, int nSpan, Pr Pred) {
if (first == last || nSpan <= 0) return last;
It lastGood = first;
It cur = first;
++cur;
for (; cur != last; ++cur) {
bool found = false;
It back = lastGood;
for (int i = nSpan; i > 0; --i, --back) {
if (Pred(*back, *cur)) {
found = true;
lastGood = back;
break;
}
if (back == first) break;
}
if (!found) {
++lastGood;
*lastGood = std::move(*cur);
}
}
++lastGood;
return lastGood;
}
这使得N
移动/复制次数不超过,Pred
调用次数不超过N * nSpan
。
您可以通过维护下一个元素的表来避免列出的这两个问题。因此,在不违反谓词的情况下,每个位置都将指向符合good
邻居条件的下一个有效位置,如下所示:
map<unsigned, unsigned> neigh_table;
while(it != end){
neigh = startneigh = it + 1;
do{
if(pred(it, neigh)) //if predicate fails, restart with a new neighbour
neigh = startneigh = neigh + 1;
else
++neigh;
}while(neigh - startneigh < range && neigh != end);
neigh_table[it-start] = startneigh - start;
it = neigh;
}
在操作结束时,您可以:
- 返回邻居的查找表供用户处理或
- 通过在函数内自己遍历映射,返回一个迭代器列表,该列表与容器分离,就像是邻居迭代器的向量/列表一样
无论哪种情况,如果不将实际容器传递给函数,都无法修改容器。这就是像stl::remove
这样的函数不修改容器长度的原因。有关如何使用stl::remove实际修改容器的示例,请参阅remove-erase习惯用法。
相关文章:
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 如何在c++中为模板函数实例创建快捷方式
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 在c代码之间共享数据的最佳方式
- 在C++中将函数压缩为两种方式
- STL映射比较器能否以某种方式获取指向映射本身的指针?
- 容器类别在STL中的工作方式
- remove_neighbors以类似STL的方式
- 我插入 STL 映射的方式是否正确?不会漏内存吗?
- 如何以特定方式在 c++ STL 中查找
- 使用STL std::将方式排序为qsort_r
- stl有助于在c++中以更快的方式搜索大数组吗
- STL 方式在容器上的循环中同时访问更多元素
- 使用stl以不同方式拆分字符串
- 如何以STL的方式在列表中找到最小的缺失整数
- 如何以优雅/快速的方式将STL字符串向量转换为char*
- 公开自定义stl风格迭代的首选方式是什么?
- 使用索引迭代STL容器的安全方式,避免使用锁
- 以一种漂亮的STL方式检查一个范围是否是另一个范围的子范围
- 如何在STL中以优美的方式复制矢量到映射