C++ 入侵rbtree中第一个元素的恒定时间测试
如何有效地判断元素是否位于侵入集或rbtree的开头?我想定义一个简单的函数C++ 入侵rbtree中第一个元素的恒定时间测试,c++,boost,C++,Boost,如何有效地判断元素是否位于侵入集或rbtree的开头?我想定义一个简单的函数prev,它返回指向树中上一项的指针,如果没有上一项,则返回nullptr。类似的next函数很容易编写,使用iterator\u to并与end()进行比较。但是,没有等效的reverse\u iterator\u to函数允许我与rend()进行比较。此外,我特别不想与begin()进行比较,因为在红黑树中这不是常数时间 有一件事似乎确实有效,那就是递减迭代器并将其与end()进行比较。这与实现配合得很好,但我在文档
prev
,它返回指向树中上一项的指针,如果没有上一项,则返回nullptr
。类似的next
函数很容易编写,使用iterator\u to
并与end()
进行比较。但是,没有等效的reverse\u iterator\u 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;
}
作为与tree.begin()的比较,成本应该不会太高。您可以从
迭代器\u到获得反向迭代器
另外,请注意,这样您就不必为prev
函数设置“全局”状态
您只需创建相应的反向迭代器。您必须+1迭代器才能获得预期的地址:
因此,我对此的看法是(奖励:无内存泄漏):
#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 << " ";
}
}
}
您没有实现prev
函数(我的实际问题),尽管您的解决方案建议使用Tree::reverse\u迭代器(Tree.iterator\u to(fp))
。这两个函数和我的prev
函数都可以工作,但是我在boost文档中找不到对这两个函数的支持。特别是,相关国家只表示它是执行定义的。boost是否提供迭代器行为的“规范”描述?另外,由于STL中的rend().base()
必须是日志时间,因此是否可以保证rend()
是常数时间?此处记录了从反向迭代器到基本迭代器的隐式转换,例如:。我同意这是一个惯例。但是很多关于图书馆的事情并没有在这个意义上被记录下来。一个承诺与标准库兼容的容器的库遵守该标准库的迭代器要求和约定是有道理的,我不知道如何保证复杂性。这可能在其他地方得到了回答,而且可能是一个很好的问题。现在我很困惑。std::reverse_迭代器与boost::intrusive::rbtree::reverse_迭代器相同吗?假设这些是同一类型有什么依据?没有人这么说。假设这样做既不合理也没有必要。我回答了你的问题,为什么不更明确地记录这些事情
#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':