Ранговое дерево в C ++ - PullRequest
       19

Ранговое дерево в C ++

8 голосов
/ 18 февраля 2010

Нам нужен ADT с функциями поиска и ранжирования.То есть, в дополнение к интерфейсу карты STL, требуется функция 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 ]

5 голосов
/ 19 февраля 2010

Ранг данного ключа K - это количество ключей, которые меньше или равны K.

Например, пусть s = {1, 3, 4, 6, 9}. Тогда ранг (1) = 1, ранг (4) = 3, ранг (9) = 5.

Функция расстояния STL () может использоваться для вычисления ранга элемента x, появляющегося в наборе s.

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

Проблема в том, что его временная сложность равна O (n).

Обратите внимание, что предложенные две карты (или наборы), проиндексированные по ключу и рангу, не являются правильным решением Проблема в том, что смена одного элемента влияет на ряды других. Например, добавление элемента 0 к вышеприведенному набору s изменяет ранги всех существующих элементов: s '= {0, 1, 3, 4, 6, 9}. ранг (1) = 2, ранг (4) = 4, ранг (9) = 6.

Спасибо.

2 голосов
/ 28 декабря 2010

Я реализовал «ранжированное красно-черное дерево», которое похоже на красно-черное дерево, за исключением того, что каждый узел хранит расстояние от предшествующего ему узла через обратный порядок, а не хранит ключ.

Это именно то, что вы хотите, за исключением того, что «ранг» первого узла равен 0, а не 1 (вы можете добавить / вычесть 1, если необходимо).

Мое решение - ОБЩЕСТВЕННЫЙ ДОМЕНна основе общедоступного руководства по регулярному красно-черному дереву.Все операции, включая вставку, удаление, поиск и определение ранга, имеют логарифмическое время по отношению к количеству элементов в структуре данных.

Вы можете найти его здесь: http://code.google.com/p/options/downloads/list

Вы должны получить последнюю версию по вышеуказанной ссылке, в настоящее время (на момент написания статьи) rrb_v4_release.cpp.

1 голос
/ 21 октября 2015

Вы можете использовать некоторые другие карты, такие как контейнеры.
сохранение размера полей может сделать дерево бинарного поиска простым для произвольного доступа.
вот моя реализация ...
стандартный стиль, итератор произвольного доступа ...
сбалансированное по размеру дерево ...
https://github.com/mm304321141/zzz_lib/blob/master/sbtree.h
и B + дерево ...
https://github.com/mm304321141/zzz_lib/blob/master/bpptree.h

0 голосов
/ 18 февраля 2010

Я бы предположил, что под 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, я могу работать немного больше, но я не хочу тратить слишком много времени в неправильном направлении.

...