«Восхождение» по двоичному дереву

#c #algorithm #binary-tree

#c #алгоритм #двоичное дерево

Вопрос:

Есть ли какой-нибудь способ подняться по дереву непосредственно к номеру, не посещая другие ветви? Например, если у меня есть номер 11, я должен посетить его, перейдя к 2, затем к 5, а затем к 11 без какого-либо поиска.

                                  0
                            /         
                           /           
                          /             
                        1                2
                      /               /    
                     /               /       
                    3        4        5       6
                   /       /       /      / 
                  /       /       /      /   
                 7     8  9    10   11  12  13  14 
  

Я убил много времени, единственное, что я получил на данный момент, это то, что для получения первого маршрута (1 или 2) числа N вам нужно (n-1) / 2, пока n не станет равным 1 или 2.
Пример:
(12 — 1)/2 => (5 — 1)/2 => 2. (7-1)/2=>(3-1)/2 => 1. (11-1)/5=>(2-1)/2 => 1.
Но в конечном итоге было бы правильно вырезать корень (0) и обрабатывать 2 как новый:

           2
         / 
        /   
       /     
     5        6
    /       / 
   /       /    
  11   12  13   14

         to

          0
         / 
        /   
       /     
     1        2
    /       / 
   /       /    
  3     4  5     6
  

Решение:

 int climb(int ID, Tree<int> t)
{

    int time = 0;
    if (tree.exists()) {
        time  = t.value();
        tree t1, t2;
        t.branches(t1, t2);
        int branch = ID;
        while (branch > 2) branch = (branch - 1)/2;
        int offset = 1;
        while (offset*2 < ID - 1) offset *= 2;
        if (aux == 1) time  = climb(ID - offset2/, a1);
        if (aux == 2) time  = climb(ID - offset, a2);
    }
    return time;
}
  

Вы можете получить доступ к ЛЮБОМУ (1, 5, 13 и т.д.) элементу полного двоичного дерева.

Комментарии:

1. Я думаю, что слово, которое вы ищете, — это «пересечение», а не «подъем». Кроме того, рекурсия является обычной сущностью решения

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

3. Это зависит от того, является ли ваше дерево идеальным двоичным деревом (все листья находятся на одинаковой глубине, и у каждого родителя есть два дочерних элемента)? Являются ли значения узлов такими же, как в примере? Если ответ на оба вопроса «да», то «да», вы можете делать то, что хотите. Если нет, то нет, вы не можете.

4. Это именно такое дерево. Среди прочего, смещение для левой ветви в два раза меньше смещения правой.

5. Я думаю, что у меня получается. смещение = 2 ^ m, так что m — номер строки, меньший 2:

Ответ №1:

Если вы хотите пропустить просмотр всех промежуточных узлов, используйте контейнер хэшей (например, std::map или std::set ) и поиск по хэшу. Бинарные деревья предназначены для рекурсивного обхода. Обратите внимание, что set это не ассоциативно, поэтому вам придется немного поработать с этим.

Если вы слишком сильно пытаетесь добавить настраиваемый код / переменные-члены в дерево / узлы дерева, вы можете в конечном итоге получить tree impl, который перегружен памятью (ответ Дэвида — очень яркий пример этого).

— править —

Если ваши идентификаторы всегда представляют собой последовательность без слишком большого количества отверстий (например, 0, 1, 2,..., 50 ИЛИ 68, 69,...,230,231 ), я рекомендую обычный старый массив! Дайте мне знать, если захотите узнать больше.

В общем, моя задача — сначала выбрать правильный контейнер / структуру, а затем, только при необходимости, внести «незначительные» изменения в саму структуру.

Комментарии:

1. Я не уверен, я все еще новичок. Думаю, я выразился не очень ясно. 0 1 2 …2N-2 — это просто ссылка, и они НЕ хранятся внутри дерева. Все дело в том, чтобы хранить меньше.

2. @user1021852 ?? в какой части вы не уверены?

3. Если вы ничего не знаете, то начните с «поиска по хэшу» и «поиска по дереву». Например. cs.bu.edu/teaching/cs113/spring-2000/hash и en.wikipedia.org/wiki/Self-balancing_binary_search_tree , тогда вы лучше поймете, что каждая структура использует внутренне.

Ответ №2:

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

В этом случае обратите внимание на следующее:

  • Узел n имеет в качестве дочерних узлов значения 2*n 1, 2* n 2
  • Если вы хотите перейти к узлу с нечетным значением K, то его родительским является узел (K-1) /2
  • Если вы хотите посетить узел с четным значением K, его родительским является узел (K-2) /2

Вы повторяете ту же процедуру, поскольку достигаете узла 0 и у вас есть все узлы, которые вам нужно посетить.

Итак, для вашего примера вы хотите посетить узел 11.

 11 is odd so its parent is (11-1)/2 = 5
5 is odd so its parent is (5-1)/2 = 2
2 is even so its parent is (2-2)/0 = 0

we have reached the root node, so you have to follow the path 0->2->5->11
  

Комментарии:

1. Вы предполагаете, что ключи всегда представляют собой полную последовательность. В этом случае, как я и предлагал, простой старый массив должен быть лучшим / самым быстрым.

2. Я уже делал это, и я использую целочисленное деление, поэтому мне все равно, если это нечетно. Но спасибо в любом случае.

3. @thekashyap полностью согласен с контейнером.

4. @user1021852 Нечетное / четное важно, если вы переходите от root к своему дочернему элементу. четный -> идти направо, нечетный -> идти налево. Итак, для последовательности 2,5,11 вам нужно взять правую ветвь, затем левую, а затем левую.

Ответ №3:

Я хотел «взобраться» на любую ветку или лист без доступа к ветвям, которые не мешают (если я поднимаюсь до ‘4’, тогда я иду напрямую 0 -> 2 -> 4). И единственным путем, который я пропустил, было смещение, которое «преобразует» ветвь в дерево (см. Вопрос).

Я получаю смещение таким образом:

 int offset = 1;
while (offset*2 < ID - 1) offset *= 2;
  

Это работает для ветви ‘2’, а смещение / 2 будет работать для ветви ‘1’.

 int climb(int ID, Tree<int> t)
{

    int time = 0;
    if (tree.exists()) {
        time  = t.value();
        tree t1, t2;
        t.branches(t1, t2);
        int branch = ID;
        while (branch > 2) branch = (branch - 1)/2;
        int offset = 1;
        while (offset*2 < ID - 1) offset *= 2;
        if (aux == 1) time  = climb(ID - offset2/, a1);
        if (aux == 2) time  = climb(ID - offset, a2);
    }
    return time;
}
  

Ответ №4:

Другим способом было создать стек:

 void solve(int n)
{
  stack<direction> path;
 //Calculate the way 
  while (n > 0)
  {
    if (n amp; 1) // if n is odd;
      path.push_back(left);
    else
      path.push_back(right);

    n = (n - 1) / 2;
  }

  //Do actual "climbing"

  while (!path.empty())
  {
    if (path.top() == left)
    {
      go left
    }
    else
    {
      go right
    }

    path.pop();
  }
}
  

Спасибо Raving_Zealot от linux.org.ru