Вставка дерева AVL не вращается должным образом, возможно проблема с рекурсией - PullRequest
0 голосов
/ 15 февраля 2020

Я уже несколько дней ломаю голову над этой проблемой, пробуя всевозможные реализации дерева AVL в JavaScript. Это самое близкое, что я получил до сих пор, но вращение работает не так, как ожидалось, и мне постоянно приходится переустанавливать this.root каждый раз, когда я вставляю новое значение. Я хочу, чтобы моя реализация могла добавлять несколько значений, поэтому я разрешаю передавать массив или одно значение (поэтому я использую очередь).

Результат теста для: bst.insert([50, 40, 30, 32, 34, 38, 39, 38.5, 55, 27] возвращается очень неправильно. Фактические значения после заказа должны возвращаться как: [27, 32, 30, 38.5, 39, 38, 50, 55, 40, 34], но возвращается [27, 30, 32, 38, 39, 55, 50, 40, 38.5, 34].

Я полагаю, что проблема возникает где-то в методе insertHelper во время рекурсии, но я не могу определить ее сам в этой точке и был бы очень признателен за sh и не злой пара глаз, чтобы проверить мой код. По сути, не все узлы повторно балансируют и рекурсивно вращаются обратно к узлу root, и я не уверен, почему моя рекурсия не может этого сделать.

getBF(node) {
    if (node === null) {
      return 0;
    }

    return this.getHeight(node.left) - this.getHeight(node.right);
  }

  getHeight(node) {
    if (node === null) {
      return -1;
    }

    return node.height;
  }

  insert(value) {
    let queue = new Plus.Queue();

    if (value === undefined) {
      return;
    } else if (Array.isArray(value)) {
      value.forEach((val) => queue.enqueue(val));
    } else {
      queue.enqueue(value);
    }

    let currentValue;
    let newNode;

    while (queue.data.length > 0) {
      currentValue = queue.dequeue();

      if (this.validData(currentValue)) {
        newNode = new Plus.TreeNode(currentValue);

        if (this.root === null) {
          this.root = newNode;
        } else {
          this.root = this.insertHelper(this.root, newNode);
        }
      } else {
        if (!this.duplicates[currentValue]) {
          this.duplicates[currentValue] = 0;
        }

        this.duplicates[currentValue] += 1;
      }
    }

    return this;
  } 

  insertHelper(root, node) {
    if (root === null) {
      root = node;
    } else if (this.compareFunction(node.val, root.val)) {
      root.left = this.insertHelper(root.left, node);
    } else {
      root.right = this.insertHelper(root.right, node);
    }

    root = this.update(root);
    return this.balance(root);
  }

  update(node) {
    let lh, rh;
    [lh, rh] = [-1, -1];

    if (node.left) {
      lh = node.left.height;
    }

    if (node.right) {
      rh = node.right.height;
    }

    node.height = 1 + Math.max(lh, rh);
    node.bf = rh - lh;
    return node;
  }

  balance(node) {
    if (node.bf > 1) {
      if (node.right.bf >= 0) {
        node = this.rotationRightRight(node);
      } else {
        node = this.rotationRightLeft(node);
      }
    } else if (node.bf < -1) {
      if (node.left.bf <= 0) {
        node = this.rotationLeftLeft(node);
      } else {
        node = this.rotationLeftRight(node);
      }
    }

    return node;
  }

  rotationLeftLeft(node) {
    let newHead = node.left;
    let t3 = newHead.right;
    newHead.right = node;
    node.left = t3;

    newHead = this.update(newHead);
    node = this.update(node);
    return newHead;
  }

  rotationLeftRight(node) {
    node.left = this.rotationRightRight(node.left);
    return this.rotationLeftLeft(node);
  }

  rotationRightRight(node) {
    let newHead = node.right;
    node.right = newHead.left;
    newHead.left = node;

    newHead = this.update(newHead);
    node = this.update(node);
    return newHead;
  }

  rotationRightLeft(node) {
    node.right = this.rotationLeftLeft(node.right);
    return this.rotationRightRight(node);
  }

The BST - это функция class, которую я использую для этого. Все эти методы являются методами функции конструктора BST. Я почти уверен, что ошибка не возникает с этим, поэтому я пропустил эту часть кода, но если вы думаете, что это поможет, я тоже загрузлю это.

Вот Node класс, с которым я работаю для отдельных узлов в дереве AVL.

Plus.TreeNode = class {
  constructor(val = null, left, right) {
    this.val = val;
    this.left = null;
    this.right = null;
    this.height = 0;
    this.bf = 0;
  }
};

И вот возвращаемое значение метода insert, описанного выше:

    { val: 34,
      left: 
       { val: 32,
         left: { val: 30, left: [Object], right: null, height: 1, bf: -1 },
         right: null,
         height: 2,
         bf: -2 },
      right: 
       { val: 38.5,
         left: { val: 38, left: null, right: null, height: 0, bf: 0 },
         right: { val: 40, left: [Object], right: [Object], height: 2, bf: 1 },
         height: 3,
         bf: 2 },
      height: 7,
      bf: 4 }

Спасибо заранее!

...