Каковы некоторые альтернативы рекурсивным алгоритмам поиска?

Я рассматриваю альтернативы алгоритму глубокого поиска, над которым я работаю. Мой код слишком длинный, чтобы публиковать здесь, но я написал упрощенную версию, которая отражает важные аспекты. Во-первых, я создал объект, который я назову 'BranchNode', который содержит несколько значений, а также массив других объектов BranchNode.

class BranchNode : IComparable<BranchNode>
{
    public BranchNode(int depth, int parentValue, Random rnd)
    {
        _nodeDelta = rnd.Next(-100, 100);
        _depth = depth + 1;
        leafValue = parentValue + _nodeDelta;

        if (depth < 10)
        {
            int children = rnd.Next(1, 10);
            branchNodes = new BranchNode[children];
            for (int i = 0; i < children; i++)
            {
                branchNodes[i] = new BranchNode(_depth, leafValue, rnd);
            }
        }
    }

    public int CompareTo(BranchNode other)
    {
        return other.leafValue.CompareTo(this.leafValue);
    }


    private int _nodeDelta;
    public BranchNode[] branchNodes;
    private int _depth;
    public int leafValue;


}

В моей реальной программе я получаю свои данные из других источников... но для этого примера я просто передаю экземпляр объекта Random в строке, которую я использую, чтобы генерировать значения для каждого BranchNode... Я также вручную создаю глубину 10, тогда как мои фактические данные будут иметь любое количество поколений.

В качестве быстрого объяснения моих целей, _nodeDelta содержит значение, присвоенное каждому BranchNode. Каждый экземпляр также поддерживает значение leafValue, которое равно текущему BranchNode _nodeDelta, суммированному с _nodeDeltas всех его предков. Я пытаюсь найти самый большой leafValue BranchNode без детей.

В настоящее время я рекурсивно перебираю иерархию, ища BranchNodes, дочерний массив BranchNodes которых равен null (a.k.a: a "бездетный" BranchNode), а затем сравнивает значение leafValue с текущим самым высоким значением leafValue. Если он больше, он становится эталоном и поиск продолжается до тех пор, пока он не посмотрит на все BranchNodes.

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

Мне было интересно, есть ли у меня какие-либо другие варианты, которые я мог бы изучить, что может привести к более быстрым результатам... особенно, я пытался обернуть голову вокруг linq, но я даже не уверен, что он построен делать то, что я ищу, или если это будет быстрее. Есть ли другие вещи, над которыми я должен смотреть?

2
29 дек. '12 в 19:29
источник поделиться
4 ответов

Возможно, вы хотите изучить альтернативную структуру индекса данных: Здесь

Это всегда зависит от работы, которую вы делаете с данными, но если вы назначаете уникальный идентификатор для каждого элемента, который хранит иерархическую форму и создавая индекс того, что вы храните, ваша оптимизация будет иметь гораздо больше смысла, чем микро -оптимизировать части того, что вы делаете.

Кроме того, это также дает совершенно другую парадигму в алгоритмах поиска, которая не использует рекурсию, а в стоимости дополнительной памяти для идентификаторов и, возможно, индекса.

1
29 дек. '12 в 19:42
источник

Я думаю, что первое, о чем вы должны подумать, возможно, уходит от N-Tree и собирается как дерево двоичного поиска.

Это означает, что все узлы имеют только 2 детей, больший ребенок и меньший ребенок.

Оттуда я бы сказал, что вы балансируете дерево поиска с чем-то вроде дерева Red-Black или AVL. Таким образом, поиск вашего дерева - O (log n).

Вот несколько ссылок, которые помогут вам начать:

http://en.wikipedia.org/wiki/Binary_search_tree http://en.wikipedia.org/wiki/AVL_tree http://en.wikipedia.org/wiki/Red-black_tree

Теперь, если вы мертвы, если у каждого node есть N дочерних узлов, вот некоторые вещи, о которых вы должны:

  • Подумайте о том, как упорядочить дочерние узлы, чтобы вы могли быстро определить, у кого самый высокий номер листа. Таким образом, при вводе нового node вы можете проверить один дочерний элемент node и быстро определить, стоит ли рекурсивно проверять его на детей.
  • Подумайте о том, как можно быстро устранить столько узлов, сколько возможно, из поиска или разбить рекурсивные вызовы как можно раньше. С деревом двоичного поиска вы можете легко найти самый большой лист node, всегда глядя только на больший ребенок. это может исключить детей N-log(n), если дерево сбалансировано.
  • Подумайте о вставке и удалении узлов. Если вы проводите здесь больше времени, вы можете сэкономить гораздо больше времени.
1
29 дек. '12 в 19:46
источник

Если вы должны посетить все листовые узлы, вы не сможете ускорить поиск: он будет проходить через все узлы, несмотря ни на что. Типичный трюк, используемый для ускорения поиска на деревьях, организует их определенным образом, что упрощает поиск дерева. Например, создав двоичное дерево поиска, выполните поиск O(Log(N)). Вы также можете сохранить некоторые полезные значения в нелистовых узлах, из которых позже вы могли бы построить ответ на свой поисковый запрос.

Например, вы можете решить, что _bestLeaf "указывает" на лист с наивысшим значением _nodeDelta всех листов под текущим поддеревом. Если вы это сделаете, ваш поиск станет поиском O(1). Однако ваши вставки и удаления станут более дорогими, потому что вам нужно будет обновить до Log-b(N) элементы на обратном пути к корню с помощью нового _bestLeaf (b - коэффициент ветвления вашего дерева).

1
29 дек. '12 в 19:46
источник

Как отмечают другие, другая структура данных может быть тем, что вы хотите.

Если вам нужно сохранить структуру данных одинаковой, рекурсия может быть развязана в циклы. Хотя этот подход, вероятно, будет немного быстрее, он не будет на порядок быстрее, но может занять меньше памяти.

0
29 дек. '12 в 19:47
источник

Посмотрите другие вопросы по меткам или Задайте вопрос