Алгоритмы. Обход дерева

Алгоритмы. Обход дерева


Давно я не писал, как то все времени не находилось. Мы говорили про деревья, давайте теперь поговорим про обход деревьев. Обходы деревьев нужны собственно для того чтоб оптимально быстрой найти необходимый элемент в дереве.

Собственно обход дерева, как и все обходы графов ( а дерево это обычный неориентированный граф ) делается двумя методами: в глубину (Depth-first) и в ширину (Breadth-first).

Какой из методов использовать?

На самом деле споров достаточно много, и если зайти на различные форумы — то вы получите огромное количество ответов, каждый из которых не факт что будет полезен для вас. Потому, для себя я решил таким образом( взято кстати с треда на stackoverflow):

  1. если вы знаете что решение где-то не далеко от вашей ноды — то лучше использовать обход в ширь, чтоб не закапываться глубоко в дерево
  2. если дерево очень глубокое, а решение редки — то лучше все таки попробовать поиск в ширь
  3. если дерево очень широкое, то можно попробовать поиск в глубь, потому как поиск в ширь может забрать слишком много времени.

Собственно, как я уже и писал, правильного ответа нет — потому надо пробовать разные варианты:) Эксперементировать всегда весело!

Так как мы будем пробовать на созданном бинарном дереве все алгоритмы, они редко бывают широкими, потому обсудим в начале поиск в глубь.

DFS. Алгоритмы в глубь имеют три типа обходов:

  1. Pre-order

Pre-order стоит использовать именно тогда, когда вы знаете что вам нужно проверить руты перед тем как проверять их листья.

В результате Pre-order обхода мы получим такой порядок :

F, B, A,D,C,E,G,I,H

Код метода:

function preOrder(node){
  if (node == null) return;
  console.log(node.value);
  preOrder(node.left);
  preOrder(node.right);
}

2.In-order

In-order обход используется как раз когда нам надо проверять в начале детей и только потом подыматься к родительским узлам.

В таком случае мы получаем просто: A,B,C,D,E,F,G,H,I

function inOrder(node){
  if (node == null) return;
  inOrder(node.left);
  console.log(node.value);
  inOrder(node.right);
}

3.Post-order

Post-order самый забавный случай — это случай когда нам нужно начать-так сказать с листов и завершить главным узлом — тоесть разложить дерево на то, как оно строилось.

В таком случае мы полчаем: A, C, E, D, B, H, I, G,F

function postOrder(node){
  if (node == null) return;
  postOrder(node.left);
  postOrder(node.right);
  console.log(node.value);
}

Как видим — код очень похож:) просто разный порядок вызовов.

BFS.

BFS точно такой же как и в графах. Все достаточно просто — мы бегаем в начале по рут ноде, потом по всем ее детям, потом по всем детям детей, и так далее.

function bfs(node){
  var queue = [];
  var values = [];
  queue.push(node);
  while(queue.length > 0){
    var tempNode = queue.shift();
    values.push(tempNode.value);
    if (tempNode.left){
      queue.push(tempNode.left);
    }
    if (tempNode.right){
      queue.push(tempNode.right);
    }
  }
  return values;
}

Собственно на этом пока все:)

Как обычно: исходники примеров вы можете найти тут.

Источник: https://medium.com/@dimko1



Report Page