Это третья из серии статей о реализации структур данных в JavaScript. Если вы новичок в структурах данных, обязательно начните сначала с Стеки.

Анализ

Двоичное дерево поиска (BST) - это древовидная структура данных на основе узлов, в которой каждый узел может иметь не более двух дочерних элементов. BST поддерживает несколько методов, общих для любого дерева поиска, таких как contains, insert и depthFirstLog, и delete. Мы поговорим об этом позже! Есть два основных способа представления BST. Я собираюсь сосредоточиться на методе с использованием узловых объектов, которые имеют ссылки на своих дочерних элементов.

Как следует из названия, BST - это просто двоичное дерево, только со следующими ограничениями, наложенными на то, куда могут идти узлы.

  • Для каждого узла (node1) каждое значение, найденное в левом поддереве node1, меньше или равно значению, найденному в node1 .
  • Для каждого узла (node1) каждое значение, найденное в правом поддереве node1, больше или равно значению, найденному в node1 .

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

Методы

У BST есть четыре основных метода:

  1. insert (value): принимает значение и размещает в дереве в правильной позиции.
  2. содержит (значение): принимает значение и возвращает логическое значение, отражающее, содержится ли значение в дереве.
  3. depthFirstLog (обратный вызов): принимает обратный вызов и выполняет его для каждого значения, содержащегося в дереве.

и иногда содержит:

  1. delete (значение): принимает значение и удаляет это конкретное значение в BST.

Давайте углубимся в методы BST

Вставлять

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

Содержит

Операция поиска выполняет двоичный поиск во многом аналогично операции вставки, чтобы определить, существует ли n.

Глубина первого журнала

Метод depthFirstLog принимает обратный вызов и применяет обратный вызов к каждому значению в BST. Это означает, что нам нужна (должна) рекурсия для обхода каждого BST, чтобы применить функцию обратного вызова к каждому узлу.

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

Псевдокод

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

Create BST constructor
  define value, right child and left child
Define insert method on prototype (value)
  Create new node with passed in value
  Create recursive function
    If current node value > value && left child is undefined
      Insert node as left child
    If current node value > value
      Recurse current node left child
    If current node value <value && right child is undefined
      Insert node as right child
    If current node value <value
      Recurse current node right child
  Call recursive function on root node
Define contains method on prototype (value)
  Create variable to hold found node
  Create recursive function
    If current node value is equal to value
      Set variable equal to true
    else if BST left child is !undefined && value < BST value 
      recurse with current node's left child
    else if BST right child is !undefined && value > BST value
      recurse with current node's right child
  Call recursive function on root node
  Return variable of found node
Define depthFirstLog method on prototype (callback)
  Create recursive function
    Use call with callback on BST and BST value
    If left child is not undefined 
      Recurse through left child
    If right child is not undefined
      Recurse through right child
  Call recursive function on root node

Сложность времени

Если вы мало знаете о временной сложности, потратьте немного времени и изучите основы, прежде чем двигаться дальше.

Методы в BST всегда начинаются с корневого узла и постепенно спускаются вниз, поэтому максимальное время, которое занимает каждая операция, зависит от высоты дерева. Например, для дерева с n узлами, у которого нет правильных дочерних элементов, потребуется O (n) времени, однако полный BST (каждый уровень, кроме последний полностью заполнен, с узлами на последнем как можно левее) имеет время наихудшего случая O (log n).

  • delete: Linear - O (n) или O (log n) в среднем случае
  • insert: Linear - O (n) или O (log n) в среднем случае
  • содержит: Linear - O (n) или O (log n) в среднем случае
  • depthFirstLog: Linear - O (n) или O (log n) в среднем случае

Код

Этот пост написал один из инструкторов Banyan Codecamp, нового учебного курса по программированию, разработанного с единственной целью: превратить начинающих программистов в способных инженеров под руководством старших инженеров. Получи высшее образование, сделай шестизначное число и учись на прекрасном острове Бали. Чтобы узнать больше, посетите www.codeinbali.com.

Вопросы на собеседовании о деревьях двоичного поиска

Будущие ответы :)

Разработайте алгоритм для поиска пути от одного узла в двоичном дереве к другому.

Для двоичного дерева проверьте, является ли оно двоичным деревом поиска.

Найдите минимальную глубину двоичного дерева поиска

Для двоичного дерева поиска и значения k найдите узел в двоичном дереве поиска, значение которого ближе всего к k.