C ++中的排名树

时间:2010-02-18 16:51:43

标签: c++ boost stl tree multiway-tree

我们需要ADT具有搜索和排名功能。 也就是说,除了STL map的接口外,还需要一个函数'int get_rank(key)'。

这种功能的标准实现需要在自平衡搜索树的每个节点中支持和更新额外的整数字段(例如,在用于STL映射/集合的黑红树中)。 但似乎,STL map / set不会这样做。

我们正在寻找一种基于标准容器(STL,Boost)的解决方案,它具有最佳的时间复杂度:   查找/添加/删除元素需要O(log n)(就像在STL map / set中一样),   通过密钥计算等级也需要O(log n)。

通过元素的等级,我们指的是元素在地图/集合的所有元素的排序序列中的位置。

实施例。   set = {0,4,6,7,8}   rank(0)= 1,rank(4)= 2,rank(6)= 3,rank(7)= 4,rank(8)= 5.

在我们看来,在上述时间复杂性约束下,问题无法通过两个地图的组合来解决,一个按键排序,另一个按等级排序。

感谢。

4 个答案:

答案 0 :(得分:5)

给定密钥K的等级是小于或等于K的密钥数。

例如,设s = {1,3,4,6,9}。 然后rank(1)= 1,rank(4)= 3,rank(9)= 5。

STL函数distance()可用于计算出现在集合中的元素x的等级。

rank = distance(s.begin(),s.find(x));

问题在于其时间复杂度为O(n)。

请注意,建议的两个按键和按列索引的映射(或集合)不是正确的解决方案。 问题是一个元素的变化会影响许多其他元素的排名。 例如,在上面的集合中添加元素0会改变所有现有元素的等级: s'= {0,1,3,4,6,9}。 rank(1)= 2,rank(4)= 4,rank(9)= 6.

感谢。

答案 1 :(得分:2)

我已经实现了一个类似于红黑树的“排名红黑树”,除了每​​个节点通过有序遍历存储距离它之前的节点的距离,而不是存储密钥。 / p>

这正是您想要的,除了第一个节点的“等级”为0而不是1(如果需要,您可以添加/减去1)。

我的解决方案是PUBLIC DOMAIN,它基于常规红黑树的公共领域教程。所有操作 - 包括插入,删除,查找和确定等级都具有相对于数据结构中元素数量的对数时间。

你可以在这里找到它: http://code.google.com/p/options/downloads/list

您应该从上面的链接获取最新版本(截至撰写本文时)rrb_v4_release.cpp。

答案 2 :(得分:1)

你可以使用像容器这样的其他地图 保持大小字段可以使二叉搜索树易于随机访问 这是我的实施......
标准样式,随机访问迭代器...
大小平衡树...
https://github.com/mm304321141/zzz_lib/blob/master/sbtree.h
和B +树......
https://github.com/mm304321141/zzz_lib/blob/master/bpptree.h

答案 3 :(得分:0)

我认为通过rank你实际上是指与根的距离,因为如果它可以与值连续存储,你就不必达到这样的长度。

我认为你可以“在外部”这样做,因为在这种情况下,排名可以从使用比较谓词的次数推断出来......

namespace detail
{
  template <class Comparator>
  class CounterComparator: Comparator
  {
  public:
    CounterComparator(size_t& counter):
        Comparator(), mCounter(&counter) {}
    CounterComparator(Comparator comp, size_t& counter):
        Comparator(comp), mCounter(&counter) {}

    template <class T, class U>
    bool operator()(T& lhs, U& rhs) const
    { 
      ++(*mCounter);
      return this->Comparator::operator()(lhs,rhs);
    }
  private:
    size_t* mCounter;
  };
} // namespace detail

template <
  class Key, 
  class Value, 
  class Cmp = std::less<Key>, 
  class Allocator = std::allocator< std::pair<const Key,Value> >
>
class SuperMap
{
  typedef detail::CounterComparator<Cmp> Comparator;
public:
  SuperMap(): mCounter(0), mData(Comparator(mCounter)) {}

  Value& operator[](const Key& key) { return mData[key]; }

  size_t rank(const Key& key) const
  { 
    mCounter = 0; mData.find(key); return mCounter;
  }

private:
  typedef std::map<Key,Value, Comparator, Allocator> data_type;

  mutable size_t mCounter;
  data_type mData;
}; // class SuperMap

int main(int argc, char* argv[])
{
  SuperMap<int,int> superMap;
  superMap[1] = 42;
  std::cout << superMap.rank(1) << std::endl;
}

// outputs
// 2

它计算了测试的数量,但是因为std::map一旦得到正确的密钥就会停止测试......它应该没问题:)尽管可能有一些偏移来推断它(1或2)取而代之的是等级。

如果你对rank给出了更好的定义,我可能会更多地工作,但我不想在错误的方向上花太多时间。