如何有效地判断元素是否位于侵入集或rbtree的开头?我想定义一个简单的函数prev
,它返回一个指向树中前一项的指针,如果没有先前的项,则返回nullptr
。使用next
并与iterator_to
进行比较,可以轻松编写类似的end()
函数。但是,没有等效的reverse_iterator_to
函数可以让我与rend()
进行比较。此外,我特别不想与begin()
进行比较,因为这不是红黑树中的恒定时间。
当然,似乎有一点工作就是减少迭代器并将其与end()
进行比较。这适用于实现,但我在文档中找不到对此的支持。在以下最小工作示例中实现prev
的最佳方式是什么?
#include <iostream>
#include <string>
#include <boost/intrusive/set.hpp>
using namespace std;
using namespace boost::intrusive;
struct foo : set_base_hook<> {
string name;
foo(const char *n) : name(n) {}
friend bool operator<(const foo &a, const foo &b) { return a.name < b.name; }
};
rbtree<foo> tree;
foo *
prev(foo *fp)
{
auto fi = tree.iterator_to(*fp);
return --fi == tree.end() ? nullptr : &*fi;
}
int
main()
{
tree.insert_equal(*new foo{"a"});
tree.insert_equal(*new foo{"b"});
tree.insert_equal(*new foo{"c"});
for (foo *fp = &*tree.find("c"); fp; fp = prev(fp))
cout << fp->name << endl;
}
更新:好的,所以我所遗漏的,这可能是间接得到的,是在STL中,begin()实际上保证是恒定时间。因此,即使通用的红黑树需要log(n)时间来查找最小元素,STL映射也不会 - 需要STL std :: map实现来缓存第一个元素。而且我认为,即使没有记录boost,也可以假设boost :: intrusive容器的行为类似于STL容器。鉴于这种假设,完全可以这么说:
foo *
prev(foo *fp)
{
auto fi = tree.iterator_to(*fp);
return fi == tree.begin() ? nullptr : &*--fi;
}
因为与tree.begin()的比较不应该太昂贵。
答案 0 :(得分:1)
您可以从iterator_to
获取反向迭代器。
另请注意there is
rbtree<>::container_from_iterator(iterator it)
,因此您的prev
功能不必具有“全局”状态。
您可以创建相应的reverse_iterator。您必须为迭代器+1以获取预期的地址:
所以我对此的看法是(奖励:没有内存泄漏):
<强> Live On Coliru 强>
#include <boost/intrusive/set.hpp>
#include <iostream>
#include <string>
#include <vector>
using namespace boost::intrusive;
struct foo : set_base_hook<> {
std::string name;
foo(char const* n) : name(n) {}
bool operator<(const foo &b) const { return name < b.name; }
};
int main()
{
std::vector<foo> v;
v.emplace_back("a");
v.emplace_back("b");
v.emplace_back("c");
using Tree = rbtree<foo>;
Tree tree;
tree.insert_unique(v.begin(), v.end());
for (auto key : { "a", "b", "c", "missing" })
{
std::cout << "\nusing key '" << key << "': ";
auto start = tree.iterator_to(*tree.find(key));
if (start != tree.end()) {
for (auto it = Tree::reverse_iterator(++start); it != tree.rend(); ++it)
std::cout << it->name << " ";
}
}
}
打印
using key 'a': a
using key 'b': b a
using key 'c': c b a
using key 'missing':