侵入式rbtree

时间:2015-05-27 22:47:14

标签: c++ boost

如何有效地判断元素是否位于侵入集或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()的比较不应该太昂贵。

1 个答案:

答案 0 :(得分:1)

您可以从iterator_to获取反向迭代器。

  

另请注意there is rbtree<>::container_from_iterator(iterator it),因此您的prev功能不必具有“全局”状态。

您可以创建相应的reverse_iterator。您必须为迭代器+1以获取预期的地址: enter image description here

所以我对此的看法是(奖励:没有内存泄漏):

<强> 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':