Двоичное дерево - обход в глубину

1

Я хочу сделать обход глубины для этого двоичного дерева:

          1
         / \
        4   5
       / \   \
      4   4   5

Здесь структура узла:

function TreeNode(data){
    this.data = data
    this.left = this.right = []

    this.addLeft = function(node){
        this.left.push(node)
    }

    this.addRight = function(node){
        this.right.push(node)
    }
}

Функция посещения (только для распечатки данных узла):

function visit(node){
    console.log(node.data)
}

Поперечная функция:

function traverse(node){
   if(node === null) return

   visit(node)

   //visit left branch
   for(node of node.left) traverse(node)

   //visit right branch
   for(node of node.right) traverse(node)
}

Добавьте двоичную древовидную структуру:

let rootNode = new TreeNode(1)
let node_4A = new TreeNode(4)
let node_4B = new TreeNode(4)
let node_4C = new TreeNode(4)
let node_5A = new TreeNode(5)
let node_5B = new TreeNode(5)

//add root node branches
rootNode.addLeft(node_4A)
rootNode.addRight(node_5A)

node_4A.addLeft(node_4B)
node_4A.addRight(node_4C)
node_5A.addRight(node_5B)

Выход:

1
4
4
4
5
5
5

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

Я не слишком хорошо знаком с стеклом вызовов Javascript, но может быть причина, по которой я запускаю 2 for циклов в рекурсивной функции?

Спасибо.

Теги:
binary-tree
depth-first-search

2 ответа

2
Лучший ответ

Вы берете ту же ссылку на объект для левой и правой.

this.left = this.right = []

Вам нужны независимые массивы:

this.left = [];
this.right = [];

Для принятия правильного узла используйте разные имена, кроме node для итерации.

function traverse(node) {
    if (!node) return;  // you never have a value of null for a node
    visit(node)

    //visit left branch
    for (let n of node.left) {
        traverse(n);
    }
    //visit right branch
    for (let n of node.right) {
        traverse(n);
    }
}

function TreeNode(data) {
    this.data = data
    this.left = [];
    this.right = [];

    this.addLeft = function (node) {
        this.left.push(node)
    }

    this.addRight = function (node) {
        this.right.push(node)
    }
}

function visit(node) {
    console.log(node.data)
}

function traverse(node) {
    if (!node) return; // you never have a value of null for a node

    visit(node)

    for (let n of node.left) {
        traverse(n);
    }

    for (let n of node.right) {
        traverse(n);
    }
}

let rootNode = new TreeNode(1)
let node_4A = new TreeNode(4)
let node_4B = new TreeNode(4)
let node_4C = new TreeNode(4)
let node_5A = new TreeNode(5)
let node_5B = new TreeNode(5)

//add root node branches
rootNode.addLeft(node_4A)
rootNode.addRight(node_5A)

node_4A.addLeft(node_4B)
node_4A.addRight(node_4C)
node_5A.addRight(node_5B)
traverse(rootNode);
  • 0
    а последние 5 напечатаны?
  • 0
    Ответ принят. Спасибо. Таким образом, я допустил две ошибки: первая использует одну и ту же ссылку для left и right массивов, а вторая использует одно и то же имя переменной в функции traverse . Является ли let необходимо? Потому что я считаю, что код работает нормально: for(currentNode of node.left) traverse(currentNode) я не использую let . Будет ли это проблемой позже?
Показать ещё 1 комментарий
0

Ты делаешь это:

 this.left = this.right = []

Таким образом, левый лист на самом деле тот же, что и правый. Ты хочешь:

 this.left = [];
 this.right = [];

Просто для удовольствия: на самом деле это будет хорошая утилита для генераторов:

 TreeNode.prototype.leftFirst = function*() {
    yield this.data;
    for(const child of this.left.concat(this.right))
       yield* child.leftFirst();
 };

Таким образом, вы можете:

 for(const node of tree.leftFirst())
    console.log(node);
  • 0
    Верный. Это моя ошибка использования той же ссылки на объект. Что такое * после function ?
  • 0
    @daniel, который превращает функцию в функцию генератора

Ещё вопросы

Сообщество Overcoder
Наверх
Меню