Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Construyendo un Binary Search Tree

21/25
Recursos

Aportes 154

Preguntas 7

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Yo aprendí a hacer las búsquedas de árboles binarios de forma recursiva (además que se ve más fancy 👀) Aquí dejo mi código:

search(value, tree = this.root) {

        if (tree == null) {
            return "El elemento no se encuentra.";
        }
        else if(value > tree.value) {
            return this.search(value, tree.right);
        }
        else if(value < tree.value) {
            return this.search(value, tree.left);
        }
        else {
            return "¡El elemento ha sido encontrado!";
        }

    }

Arbol Binario
La siguiente imagen ayuda a explicar lo que se esta haciendo en el código fuente.

Una característica que me encanta de los árboles binarios es que su implementación es muy fácil de realizar haciendo uso de arreglos.

¿Cuáles son las ganancias de realizarlo usando simplemente arreglos? Simple, el espacio utilizado es muchísimo menor al utilizado por objetos y cuando tenemos un árbol binario completo el desperdicio de espacio es 0.

¿Qué hay que tener en cuenta? Unos simples métodos que podemos obtener con fórmulas matemática super básicas:

  • Obtener el indice padre del nodo actual = Math.floor((index - 1) / 2)
  • Obtener el indice del hijo de la izquierda del nodo actual = 2 * index + 1
  • Obtener el indice del hijo de la derecha del nodo actual = 2 * index + 2

Aquí paso mi código con el ejercicio implementado haciendo uso de un array como estructura de datos para reflejar un árbol binario.

class BinaryTree {
  constructor() {
    this.data = [];
  }

  add(newValue) {
    let currentNode = 0;

    while (this.getData(currentNode) !== undefined) {
      if (newValue < this.getData(currentNode)) {
        currentNode = this.getLeftChild(currentNode);
      } else {
        currentNode = this.getRightChild(currentNode);
      }
    }

    this.data[currentNode] = newValue;
  }

  getData(index) {
    return this.data[index];
  }

  getParent(index) {
    return Math.floor((index - 1) / 2);
  }

  getLeftChild(index) {
    return 2 * index + 1;
  }

  getRightChild(index) {
    return 2 * index + 2;
  }

  search(value) {
    let currentNode = 0;

    while (this.getData(currentNode) != value) {
      if (value < this.getData(currentNode)) {
        currentNode = this.getLeftChild(currentNode);
      } else {
        currentNode = this.getRightChild(currentNode);
      }
    }

    return {
      found: currentNode != null,
      data: {
        value,
        index: currentNode,
        parentValue: this.getData(this.getParent(currentNode)),
        left: this.getData(this.getLeftChild(currentNode)),
        right: this.getData(this.getRightChild(currentNode)),
      },
    };
  }
}

const binaryTree = new BinaryTree();
binaryTree.add(10);
binaryTree.add(4);
binaryTree.add(2);
binaryTree.add(8);
binaryTree.add(20);
binaryTree.add(17);
binaryTree.add(170);

console.log(binaryTree.data);
console.log(binaryTree.search(8));

Lo que está raro en ese árbol es que el “10” NO debería ir ahí, esto porque cualquier cosa que esté del lado del descendiente derecho del 33 debería ser mayor a 33 ^^

El método search me quedó así:

    search(value) {
        let currentNode = this.root
        while (currentNode && currentNode.value != value) {
            if (value < currentNode.value) {
                currentNode = currentNode.left
            } else if (value > currentNode.value) {
                currentNode = currentNode.right
            }
        }
        if (!currentNode) return false
        return currentNode
    }```

Mi código quedo así:

  search(value) {
    let current = this.root;
    while( current && current.value != value ) {
      if( value < current.value) {
        current = current.left;
      } else {
        current = current.right;
      }
    }
    return current;
  }

🐱‍💻 Construyendo un Binary Search Tree en Dart.

class Node {
  var left;
  var right;
  var value;

  Node(this.value);
}

class BinarySearchTree {
  var root;

  dynamic insert(var value) {
    final newNode = Node(value);
    if (root == null) {
      root = newNode;
    } else {
      var currentNode = root;
      while (true) {
        if (value < currentNode.value) {
          if (!currentNode.left) {
            currentNode.left = newNode;
            return this;
          }
          currentNode = currentNode.left;
        } else {
          if (!currentNode.right) {
            currentNode.right = newNode;
            return this;
          }
          currentNode = currentNode.right;
        }
      }
    }
  }
}
import 'tree.dart';

void main(List<String> arguments){
  final tree = BinarySearchTree();
  tree.insert(10);
  print(tree.root);
}

Este seria mi aporte sobre el método delete, el cual sigue casi la misma lógica que el search, solo que identifica el valor que quiero buscar antes de asignarlo al currentNode haciendo que pueda eliminar este de forma facil

delete(value){
        let currentNode = this.root;

        if (this.root.value === value) {
            delete this.root;
            return this;
        }

        while (true) {
            if (value < currentNode.value) {
                if (value === currentNode.left.value) {
                    currentNode.left = null;
                    return this;
                }
                currentNode = currentNode.left;
            } else {
                if (value === currentNode.right.value) {
                    currentNode.right = null;
                    return this;
                }
                currentNode = currentNode.right;
            }
        }
    }

Mi método Search haciendo las validaciones desde el principio y usando continue y break.

search(value){
        let pointer = this.root;
        while(pointer){
            if (pointer.value ===  value) {
                return pointer;
            }
            else if(value < pointer.value && pointer.left){
                pointer = pointer.left;
                continue;
            }else if(pointer.right){
                pointer =  pointer.right;
                continue;
            }
            break;
        }
        return "Elemento no encontrado";
    }

Hola! Les comparto mi solución del reto 😁👨‍💻

class Node {
  constructor(value) {
    this.value = value
    this.left = null
    this.right = null
  }
}

class BinaryTree {
  constructor() {
    this.root = null
  }

  insert(value) {
    const newNode = new Node(value)
    if (!this.root) {
      this.root = newNode
    } else {
      let currentNode = this.root
      while (true) {
        if (currentNode.value < value) {
          if (!currentNode.right) {
            currentNode.right = newNode
            return this
          } else {
            currentNode = currentNode.right
          }
        } else {
          if (!currentNode.left) {
            currentNode.left = newNode
            return this
          } else {
            currentNode = currentNode.left
          }
        }
      }
    }
  }

  search(value) {
    let currentNode = this.root
    if (!currentNode.right && !currentNode.left) {
      return currentNode.root
    }
    while (true) {
      if (currentNode.value < value) {
        if (!currentNode.right) {
          return 'No se ha encontrado el valor 😥'
        } else {
          currentNode = currentNode.right
        }
      } else if (currentNode.value > value) {
        if (!currentNode.left) {
          return 'No se ha encontrado el valor 😥'
        } else {
          currentNode = currentNode.left
        }
      } else if (currentNode.value === value) {
        return 'Se ha encontrado el valor 😃 ' + currentNode.value
      }
    }
  }
}

const myTree = new BinaryTree()

myTree.insert(101)
myTree.insert(33)
myTree.insert(105)
myTree.insert(9)
myTree.insert(39)
myTree.insert(104)
myTree.insert(144)
console.log(myTree.search(108))

Hola compañeros!. Les comparto mi solución al reto 🤗

search(value):

Les comparto mi código
Implementé una verificación para impedir que se ingresen valores repetidos ya que no tendría sentido alguno

class BinarySearchTree {
  constructor() {
    this.root = null;
  }
  insert(value) {
    const node = this.check(value);
    if(node) {
      return new Error("Existing value");
    }
    const newNode = new Node(value);
    if(!this.root) {
      this.root = newNode;
      return this;
    } else {
      let currentNode = this.root;
      while(true) {
        if(value < currentNode.value) {
          if(!currentNode.left) {
            currentNode.left = newNode;
            return this;
          }
          currentNode = currentNode.left;
        } else {
          if(!currentNode.right) {
            currentNode.right = newNode;
            return this;
          }
          currentNode = currentNode.right;
        }
      }
    }
  }
  search(value) {
    const node = this.check(value);
    if(node) {
      return node;
    }
    return new Error("Non-existent value");
  }
  check(value) {
    let currentNode = this.root;
    if(!currentNode) {
      return false;
    }
    while(true) {
      if(currentNode.value === value) {
        return currentNode;
      }
      if(value < currentNode.value) {
        currentNode = currentNode.left;
      } else {
        currentNode = currentNode.right;
      }
      if(!currentNode) {
        return false;
      }
    }
  }
}

Reto completado!!! así hice el método de buscar:

    search (valor) {
        if (this.root === null) {
            return "No hay datos para poder buscar";
        }

        let currentNode = this.root;

        while (true) {
            
            // Lo encontraste?
            if (currentNode.value === valor) {
                return currentNode;
            }

            // Es mayor al actual?
            if (currentNode.value < valor) {
                if (currentNode.right === null) {
                    return "Este dato no existe";
                } else {
                    // Desplazo a la derecha
                    currentNode = currentNode.right;
                }
            } else {
                if (currentNode.left === null) {
                    return "Este dato no existe";
                } else {
                    // Desplazo a la izquierda
                    currentNode = currentNode.left;
                }
            }
        }
    }
}

// Instanciar
const Tree = new TreeSearch();
// Insertar datos
Tree.insert(10)
Tree.insert(4)
Tree.insert(2)
Tree.insert(20)
Tree.insert(15)
Tree.insert(30)

/** RESULTADO:
 *
 *          10
 *      /       \  
 *     4        20
 *   /        /    \
 *  2       15     30
 *
 */

 // Búsqueda - Funciona
 Tree.search(10)
 Tree.search(4)
 Tree.search(20)
 Tree.search(15)
 // Búsqueda - Error
 Tree.search(33) // Resultado: "Este dato no existe"

Listo! está realizado el método search, también estoy evitando que se repitan números en insert, además cree un reorganizador de árbol por si le quieren dar una vista, es el que mencionó que no veríamos en esta clase, lo realice para aprender a reorganizar un árbol y darle peso a los dos lados correctamente, es una función que cuando la llamas optimiza el arbol reinsertando nuevamente los valores con un nuevo root como centro.

class Node {
  constructor(value) {
    this.leftdown = null;
    this.rightdown = null;
    this.value = value;
  }
}

class BinarySearchTree {
  constructor() {
    this.root = null;
    this.container = {};
  }
  reorder() {
    const arrayArray = Object.entries(this.container);
    let arrayClean = [];
    for(let i = 0 ; arrayArray.length > i; i++) {
      arrayClean[i] = arrayArray[i][1];
    }
    let middle = arrayArray.length
    middle = parseInt(middle/2) 
    this.root = new Node(arrayClean[middle])
    for(let i = 0; arrayClean.length > i; i++) {
      this.insert(arrayClean[i]);
    }
    return arrayClean;
  }
  insert(value) {
    if(value === Number) {  
      const newNode = new Node(value);
      let currentNode = this.root;
  
      if(!this.root) {
        this.root = newNode;
        this.container[this.root.value] = this.root.value
        return this;
      } else {
        while(true) {
          if (value == currentNode.value) {
            return "If you want to update the node, please use 'update'"
          }
          if(value < currentNode.value) {
            if (!currentNode.leftdown) {
              currentNode.leftdown = newNode;
              this.container[currentNode.leftdown.value] = currentNode.leftdown.value
              return this;
            } else {
              currentNode = currentNode.leftdown;
            }
          } else {
            if (!currentNode.rightdown) {
              currentNode.rightdown = newNode;
              this.container[currentNode.rightdown.value] = currentNode.rightdown.value
              return this;
            } else {
              currentNode = currentNode.rightdown;
            }
          }
        }
      }
    } else {
        return `You need to enter data type Number, ${value} it's not valid`
    }

  }
  update(value) {
    if(value === Number) {  
      const newNode = new Node(value);
      let currentNode = this.root;
      if(!this.root) {
        this.root = newNode;
        return this;
      } else {
        while(true) {
          if (value == currentNode.value) {
            const beforeitem = currentNode;
            currentNode = newNode;
            return `Was update the before node ${beforeitem.value} to ${currentNode.value}`
          } else if(value < currentNode.value) {
            if (currentNode.leftdown) {
              currentNode = currentNode.leftdown;
            } 
          } else {
            if (currentNode.rightdown) {
              currentNode = currentNode.rightdown;
            }
          }
        }
      }
    } else {
        return `You need to enter data type Number, ${value} it's not valid`
    }
  }
  search(value) {
    if(value === Number) {  
    } else {
        return `You need to enter data type Number, ${value} it's not valid`
    }
    try {
      let currentNode = this.root;
      if(value === Number) {
        if(this.root) {
          while(true) {
            if(value == currentNode.value) {
              return currentNode
            } else if(value < currentNode.value) {
              if (currentNode.leftdown) {
                currentNode = currentNode.leftdown;
              } else {
                return `Node with value ${value} not was found`;
              }
            } else {
              if (currentNode.rightdown) {
                currentNode = currentNode.rightdown;
              } else {
                return `Node with value ${value} not was found`;
              }
            }
          }
        } else {
          return "There're not data, use instance-->> .insert(value) to enter data"
        }
      } else {
        return `You need to enter data type Number, ${value} it's not valid`
      }
    } catch(err) {
      logMyErrors(err.prototype.message)
    }


  }

}

const tree = new BinarySearchTree();

tree.insert(2);
tree.insert(3);
tree.insert(12);
tree.insert(87);
tree.insert(7);
tree.insert(42);
tree.insert(54);
tree.insert(67);
tree.insert(2);
tree.insert(1);
tree.insert(6);
tree.insert(10);
tree.insert(3);
tree.search(b);

//CÓDIGO A PROBAR

tree.update(3);
tree.search(2);
tree.container
tree.reorder()

Reto de clase cumplido mas bonus 😁

En la clase pasada no solo se hablo también del buscar si no del eliminar, se que a Fredy no le gusta la recursividad, pero Fredy no esta aquí jejeje 😉, si alguien puede sin recursividad me encantaría verlo.

class BinarySearchTree {
  constructor() {
    this.root = null;
  }
  insert(value) {
    const newNode = new Node(value);
    if (!this.root) {
      this.root = newNode;
    } else {
      let currentNode = this.root;
      while (true) {
        if (value < currentNode.value) {
          if (!currentNode.left) {
            currentNode.left = newNode;
            return this;
          }
          currentNode = currentNode.left;
        } else {
          if (!currentNode.right) {
            currentNode.right = newNode;
            return this;
          }
          currentNode = currentNode.right;
        }
      }
    }
  }
  search(value) {
    if (this.root.value === value) return this.root;
    let currentNode = this.root;
    while (true) {
      if (value < currentNode.value) {
        if (currentNode.left.value === value) {
          return currentNode.left;
        }
        currentNode = currentNode.left;
      }
      if (value > currentNode.value) {
        if (currentNode.right.value === value) {
          return currentNode.right;
        }
        currentNode = currentNode.right;
      }
    }
  }
  delete(value) {
    if (this.root.value === value) return this.root;
    let currentNode = this.root;
    while (true) {
      if (value < currentNode.value) {
        if (currentNode.left.value === value) {
          const DeleteNode = currentNode.left;
          currentNode.left = null;
          const sons = this.getSons(DeleteNode);
          if (sons.length > 0) {
            sons.forEach((element) => {
              this.insert(element);
            });
          }
          return DeleteNode;
        }
        currentNode = currentNode.left;
      }
      if (value > currentNode.value) {
        if (currentNode.right.value === value) {
          const DeleteNode = currentNode.right;
          currentNode.right = null;
          const sons = this.getSons(DeleteNode);
          if (sons.length > 0) {
            sons.forEach((element) => {
              this.insert(element);
            });
          }
          return DeleteNode;
        }
        currentNode = currentNode.right;
      }
    }
  }
  getSons(currentNode) {
    const sons = [];
    if (currentNode.left) {
      sons.push(currentNode.left.value);
      sons.push(...this.getSons(currentNode.left));
    }

    if (currentNode.right) {
      sons.push(currentNode.right.value);
      sons.push(...this.getSons(currentNode.right));
    }
    return sons;
  }
}

Este es el codigo que implemente para hacer el binary search tree:

function Node(value) {
    this.Leftchild = null
    this.Rightchild = null
    this.value = value
}

class BinaryStree {
    constructor(value = null) {
        if (!value instanceof Node && value) throw new Error("The parameter has to be a instance of Node");
        this._root = value
        if(value) {
            this.length = 1;
        }else 
            this.length = 0;
    }
    search(value) {
        const searchNode = this._searchCorrectNode(value)
        if (!searchNode) {
            console.log("The searched node doesn´t exist")
            return;
        }
        return searchNode
    }
    insert(value) {
        const newNode = new Node(value)
        if (!this._root) {
            this._root = newNode
        }
        this._searchCorrectNode(value, newNode)
        return this._root
    }
    delete(value) {
        const searchNode = this._searchCorrectNode(value)
        if (!searchNode) {
            console.log("The value to be deleted doesn´t exist")
            return;
        }
        const parentNode = this._searchParentNode(value)
        console.log(parentNode)
        if (searchNode.value > parentNode.value) {
            const rightNode = searchNode.Rightchild 
            const leftNode = searchNode.Leftchild
            const deletedNode = searchNode
            delete parentNode.Rightchild;
            parentNode.Rightchild  =  rightNode
            if(leftNode){
                this._searchCorrectNode(leftNode.value, leftNode)
            }
            return deletedNode;
        }else {
            const rightNode = searchNode.Rightchild
            const leftNode = searchNode.Leftchild 
            const deletedNode = searchNode
            delete parentNode.Leftchild;

            parentNode.Leftchild  =  leftNode
            if(rightNode) {
                this._searchCorrectNode(rightNode.value, rightNode)
            }
            return deletedNode;
        }
        

    }
    _searchParentNode(value) {
        let targetNode = this._root
        let parentNode = null
        while(true) {
            if(!targetNode) return null;

            
            if(targetNode.value === value) {
                return parentNode;
            }

            if (targetNode.value > value) {
                parentNode = targetNode
                targetNode = targetNode.Leftchild
            }else {
                parentNode = targetNode
                targetNode = targetNode.Rightchild
            }
        }
    }
    _searchCorrectNode(value, newNode = null) {
        let targetNode = this._root
        
        while(true) {
            if(!targetNode) return null;

            
            if(targetNode.value === value) {
                return targetNode;
            }

            if (targetNode.value > value) {
                if(!targetNode.Leftchild && newNode) { 
                    targetNode.Leftchild = newNode
                    break
                }
                targetNode = targetNode.Leftchild
            }else {
                if(!targetNode.Rightchild && newNode){
                    targetNode.Rightchild = newNode
                    break;
                }
                targetNode = targetNode.Rightchild
            }
        }
        // Finalización del While

    }

}

function Node(value) {
this.Leftchild = null
this.Rightchild = null
this.value = value
}

class BinaryStree {
constructor(value = null) {
if (!value instanceof Node && value) throw new Error(“The parameter has to be a instance of Node”);
this._root = value
if(value) {
this.length = 1;
}else
this.length = 0;
}
search(value) {
const searchNode = this._searchCorrectNode(value)
if (!searchNode) {
console.log(“The searched node doesn´t exist”)
return;
}
return searchNode
}
insert(value) {
const newNode = new Node(value)
if (!this._root) {
this._root = newNode
}
this._searchCorrectNode(value, newNode)
return this._root
}
delete(value) {
const searchNode = this._searchCorrectNode(value)
if (!searchNode) {
console.log(“The value to be deleted doesn´t exist”)
return;
}
const parentNode = this._searchParentNode(value)
console.log(parentNode)
if (searchNode.value > parentNode.value) {
const rightNode = searchNode.Rightchild
const leftNode = searchNode.Leftchild
const deletedNode = searchNode
delete parentNode.Rightchild;
parentNode.Rightchild = rightNode
if(leftNode){
this._searchCorrectNode(leftNode.value, leftNode)
}
return deletedNode;
}else {
const rightNode = searchNode.Rightchild
const leftNode = searchNode.Leftchild
const deletedNode = searchNode
delete parentNode.Leftchild;

        parentNode.Leftchild  =  leftNode
        if(rightNode) {
            this._searchCorrectNode(rightNode.value, rightNode)
        }
        return deletedNode;
    }
    

}
_searchParentNode(value) {
    let targetNode = this._root
    let parentNode = null
    while(true) {
        if(!targetNode) return null;

        
        if(targetNode.value === value) {
            return parentNode;
        }

        if (targetNode.value > value) {
            parentNode = targetNode
            targetNode = targetNode.Leftchild
        }else {
            parentNode = targetNode
            targetNode = targetNode.Rightchild
        }
    }
}
_searchCorrectNode(value, newNode = null) {
    let targetNode = this._root
    
    while(true) {
        if(!targetNode) return null;

        
        if(targetNode.value === value) {
            return targetNode;
        }

        if (targetNode.value > value) {
            if(!targetNode.Leftchild && newNode) { 
                targetNode.Leftchild = newNode
                break
            }
            targetNode = targetNode.Leftchild
        }else {
            if(!targetNode.Rightchild && newNode){
                targetNode.Rightchild = newNode
                break;
            }
            targetNode = targetNode.Rightchild
        }
    }
    // Finalización del While

}

}

Aca les dejo el que hice y le hice una pequeña validacion para saber si el valor existe o no

<code

	search(value) {
    let currentNode = this.root
    while(1) {
      if (currentNode.left === null && currentNode.right === null) {
        return "El elemento con este valor no se ha encontrado"
      } else if (value === currentNode.value) {
      return currentNode
      } else if (value < currentNode.value) {
        currentNode = currentNode.left
      } else {
        currentNode = currentNode.right
      }
    }
  }

> 

Tengo la sensacion de que use los if en exceso, alguien me dice si es algo malo?

search(number) {
    if(number === this.root.value) {
      return this.root
    } else {
      let currentNode = this.root
      while(true) {
        if(!currentNode) {
          return "Este nodo no existe"
        } else {
          if(number < currentNode.value) {
            if(currentNode.left) {
              if(number === currentNode.left.value) {
                return currentNode.left
              } else {
                currentNode = currentNode.left
              }
            } else {
              return "Este nodo no existe"
            }
          } else if(number > currentNode.value) {
            if (currentNode.right) {
              if(number === currentNode.right.value) {
                return currentNode.right
              } else {
                currentNode = currentNode.right
              }
            } else {
              return "Este nodo no existe"
            }
          } else {
            return "Inserta el numero que quieres buscar"
          }
        }
      }
    }
  }

Comparto mi solución:

//    10
//  4     20
// 2 8  17 170

class Node{
    constructor(value){
        this.left = null;
        this.right = null;
        this.value = value;
    }
}

class BinarySearchTree{
    constructor(){
        this.root = null
    }
    insert(value){
        const node = new Node(value);
        if(this.root === null){
            this.root = node;
        }
        else{
            let currentNode = this.root;
            while(true){
                if(value < currentNode.value){
                    if(!currentNode.left){
                        currentNode.left = node;
                        return this;
                    }
                    currentNode = currentNode.left
                }
                else{
                    if(!currentNode.right){
                        currentNode.right = node;
                        return this;
                    }
                    currentNode = currentNode.right;
                }
            }
        }
    }
    search(value){
        if(!this.root){
            return `El arbol esta vacio`;
        }
        else{
            let currentNode = this.root
            while(true){
                if(value == currentNode.value){
                    return currentNode;
                }
                else if(value < currentNode.value){
                    if(!currentNode.left){
                        return `No existe el dato buscado `;
                    }
                    currentNode = currentNode.left;
                }
                else{
                    if(!currentNode.right){
                        return `No existe el dato buscado `;
                    }
                    currentNode =currentNode.right;
                }
            }
        } 
    }
}

const myTree = new BinarySearchTree();
myTree.insert(10);
myTree.insert(20);
myTree.insert(4);
myTree.insert(2);
myTree.insert(17);
myTree.insert(170);
myTree.insert(8);
myTree.search(170);

Veo en los ejemplos muchas funciones resueltas con recursividad lo que las hace más sencillas de entender pero tienen un gran problema de rendimiento por consumo de memoria y pueden pueden llenar el call stack de JavaScript. Por ello en producción no suelen usarse funciones recursivas.

Dejo un ejemplo que he desarrollado del delete y el search sin recursividad para que no tenga problemas de rendimiento.

class Node<T> {
  public left: Node<T> | null = null;
  public right: Node<T> | null = null;

  constructor(
    public value: T,
  ) {
  }
}

export class BinarySearchTree<T> {
  private root: Node<T> | null = null;

  constructor() {
  }

  insert(value: T): void {
    const newNode = new Node(value);
    if (this.root === null) {
      this.root = newNode;
      return;
    }
    let currentNode = this.root;
    while (true) {
      if (value < currentNode.value) {
        if (currentNode.left === null) {
          currentNode.left = newNode;
          return;
        }
        currentNode = currentNode.left;
      } else {
        if (currentNode.right === null) {
          currentNode.right = newNode;
          return;
        }
        currentNode = currentNode.right;
      }
    }
  }

  search(value: T): Node<T> | null {
    if (this.root === null) {
      return null;
    }
    let currentNode = this.root;
    while (currentNode !== null) {
      if (value < currentNode.value) {
        if (currentNode.left === null) {
          return null;
        }
        currentNode = currentNode.left;
      } else if (value > currentNode.value) {
        if (currentNode.right === null) {
          return null;
        }
        currentNode = currentNode.right;
      } else {
        return currentNode;
      }
    }
    return null;
  }

  delete(value: T): Node<T> | null {
    if (this.root === null) { // tree is empty
      return null;
    }

    let currentNode = this.root;
    let currentNodePosition: 'right' | 'left';
    let parentNode = null;

    while (currentNode !== null) { //Empezamos a buscar el nodo y su padre
      if (value < currentNode.value) {
        if (currentNode.left === null) { // No encontramos retornamos null
          return null;
        }
        parentNode = currentNode;
        currentNode = currentNode.left;
        currentNodePosition = 'left';
      } else if (value > currentNode.value) {
        if (currentNode.right === null) { // No encontramos retornamos null
          return null;
        }
        parentNode = currentNode;
        currentNode = currentNode.right;
        currentNodePosition = 'right';
      } else { //A partir de aquí hemos encontrado el nodo a eliminar
        if (parentNode === null) { // El nodo a eliminar es el root
          if (currentNode.left === null && currentNode.right === null) { //No tiene hijos
            this.root = null;
            return currentNode;
          } else if (currentNode.left && currentNode.right) { //Tiene ambos hijos
            const nodeToChange = this.searchLeafToChange();
            nodeToChange.right = currentNode.right;
            nodeToChange.left = currentNode.left;
            this.root = nodeToChange;
            return currentNode;
          } else if (currentNode.left !== null) { //Solo tiene hijo a la izquierda
            this.root = currentNode.left;
            return currentNode;
          } else { //Solo tiene hijo a la derecha
            this.root = currentNode.right;
            return currentNode;
          }

        } else if (currentNode.left === null && currentNode.right === null) { //El nodo a eliminar es una hoja
          parentNode[currentNodePosition!] = null;
          return currentNode;

        } else if (currentNode.left && currentNode.right) { //El nodo a eliminar es intermedio y tiene ambos hijos
          const nodeToChange = this.searchLeafToChange();
          nodeToChange.left = currentNode.left;
          nodeToChange.right = currentNode.right;
          parentNode[currentNodePosition!] = nodeToChange;
          return currentNode;

        } else if (currentNode.left !== null) { //El nodo a eliminar es intermedio y solo tiene hijo a la izquierda
          parentNode[currentNodePosition!] = currentNode.left;
          return currentNode;
        } else { //El nodo a eliminar es intermedio y solo tiene hijo a la derecha
          parentNode[currentNodePosition!] = currentNode.right;
          return currentNode;
        }
      }
    }
    return currentNode;
  }

  //Busca el nodo más pequeño de la parte derecha del root, lo elimina y lo devuelve.
  private searchLeafToChange(): Node<T> {
    if (!this.root?.right) {
      return this.root!;
    }
    let currentNode = this.root.right;
    let parentNode = this.root;

    while (true) {
      if (currentNode.left !== null) { //Buscamos el nodo más pequeño
        parentNode = currentNode;
        currentNode = currentNode.left;
      } else if (currentNode.right === null) { //No tiene hijos estamos en una hoja
        parentNode.left = null;
        return currentNode;
      } else { //Tiene hijo a la derecha
        parentNode.left = currentNode.right;
        return currentNode;
      }
    }
  }
}

const tree = new BinarySearchTree<number>();

tree.insert(10);
//        10
tree.insert(4);
//        10
//     /
//   4
tree.insert(20);
//        10
//     /      \
//   4         20
tree.insert(2);
//        10
//     /      \
//   4         20
//  /
// 2
tree.insert(8);
//        10
//     /      \
//   4         20
//  /  \
// 2    8
tree.insert(17);
//        10
//     /      \
//   4         20
//  /  \      /
// 2    8   17
tree.insert(170);
//        10
//     /      \
//   4         20
//  /  \      /  \
// 2    8   17    170

// console.log(tree);

//Probando a borrar una hoja el número 8
// console.log('search value 8: ', tree.search(8));
// console.log('search value 4: ', tree.search(4));
// console.log('delete 8: ', tree.delete(8));
// console.log('search value 4: ', tree.search(4));
//        10
//     /      \
//   4         20
//  /         /  \
// 2        17    170

//Probando a borrar el root
// console.log(tree);
// console.log('delete root 10: ', tree.delete(10));
// console.log(tree);
//        17
//     /      \
//   4         20
//  /  \         \
// 2    8         170

//Probando a eliminar un nodo intermedio con ambos hijos el 20
// console.log('search root 10: ', tree.search(10));
// console.log('search value 20: ', tree.search(20));
// console.log('delete 20: ', tree.delete(20));
// console.log('search root 10: ', tree.search(10));
//        10
//     /      \
//   4         17
//  /  \         \
// 2    8         170


Se suele tardar un poco más en implementar pero aumenta mucho el rendimiento.

  search(value) {
    let currentNode = this.root;

    while (true) {
      if (!currentNode) {
        return "Not found";
      }

      if (value === currentNode.value) {
        return currentNode;
      }

      if (value < currentNode.value) {
        currentNode = currentNode.left;
      } else {
        currentNode = currentNode.right;
      }
    }
  }

Les comparto mi metodo Search y Remove. Me parece que remove esta bastante complejo de leer, bienvenidas sus sugerencias.
La idea es que unicamente borre el nodo y no toda la cadena debajo del nodo, la regla que plantee es:
Si el nodo a borrar es mayor que su nodo previo, debe de ascender el nodo menor de el nodo a borrar.
Y visversa en el caso de que sea menor a su nodo previo, debe ascender el nodo mayor de el nodo a borrar.

Me queda pendiente aplicar la logica para cuando sea root, pero quiero pensar que eya estoy muy cerca.

search(value){
        if(this.root === null){
            throw new Error('This tree its empty')
        }

        let currentNode = this.root
        while(true){
            if(value === currentNode.value){
                return currentNode
            } else if(value < currentNode.value){
                currentNode = currentNode.left
            } else {
                currentNode = currentNode.right
            }
        }
    }
    remove(value){
        if(this.root === null){
            throw new Error('This tree its empty')
        }

        let currentNode = this.root
        let prevNode
        let firstHoldingNode
        let pointer
        while(true){
            if(value === currentNode.value){
                if (value > prevNode.value){
                    firstHoldingNode = currentNode.right;
                    pointer = firstHoldingNode;
                    prevNode.right = currentNode.left;
                    currentNode = prevNode.right
                    while(true){
                        if(pointer.left === null){
                            pointer.left = currentNode.right
                            currentNode.right = firstHoldingNode
                            return prevNode
                        }
                        pointer = pointer.left
                    }
                } else {
                    firstHoldingNode = currentNode.left;
                    pointer = firstHoldingNode;
                    prevNode.left = currentNode.right;
                    currentNode = prevNode.left
                    while(true){
                        if(pointer.right === null){
                            pointer.right = currentNode.right
                            currentNode.left = firstHoldingNode
                            return prevNode
                        }
                        pointer = pointer.right
                    }
                }
            } else if(value < currentNode.value){
                prevNode = currentNode
                currentNode = currentNode.left
            } else {
                prevNode = currentNode
                currentNode = currentNode.right
            }
        }

    }
 search(value) {
    if (!this.root) {
        return false;
    }
    let currentNode = this.root;
    while (currentNode) {
        if (value < currentNode.value) {
            currentNode = currentNode.left;
            } else if (value > currentNode.value) {
                currentNode = currentNode.right;
            } else if (value === currentNode.value) {
                return currentNode;
            }
        }
    return false;
    }

De esta forma lo solucione yo, espero les sirva 😃


class Node {
    constructor (value){
        this.value = value;
        this.right = null;
        this.left = null;
    }
}

class BinarySearchTree {
    constructor (){
        this.root = null
    }

    search(value, node = this.root){
        if(node === null){
            return 'value not found'
        }
        if(node.value === value){
            return node
        }
        if(node.value > value){
            return this.search(value, node.left)
        }
        if(node.value < value){
            return this.search(value, node.right)
        }
    }

    searchSlot(value, node= this.root){
        if(node.value > value){
            if(node.left === null){
                return {
                    node: node,
                    toAttach: 'left'
                }
            } else {
                return this.searchSlot(value, node.left)
            }
        }
        if(node.value < value){
            if(node.right === null){
                return {
                    node: node,
                    toAttach: 'right'
                }
            } else {
                return this.searchSlot(value, node.right)
            }
        }
    }

    insert(value){
        const newNode = new Node (value);

        if (this.root === null){
            this.root = newNode;
        }
        else{
            let res = this.searchSlot(value)
            let nodeToAttach = res.node
            let side = res.toAttach
            nodeToAttach[side] = newNode
        }
        return this
    }

}
search(value) {
  let currentNode = this.root;
  while(currentNode) {
    if (currentNode.value === value) {
      return currentNode;
    } else if (currentNode.value > value) {
      currentNode = currentNode.left;
    } else {
      currentNode = currentNode.right;
    }
  }
  return
}

Aquí mi código de como hice la búsqueda:

search(value) {
        if(!this.root) return "No hay nodos aun";
        let currentNode = this.root;

        while (true){
            if (value == currentNode.value) return currentNode;
            if (value < currentNode.value) {
                if(!currentNode.left) return "valor no encontrado";
                currentNode = currentNode.left;
            } else {
                if (!currentNode.right) return "valor no encontrado";
                currentNode = currentNode.right;
            }
        }
    }

Comparto mi solución propuesta.

searchNode(node, value) {
  if (node === null) return undefined;
  if (node.value === value) return node;

  if (value < node.value) {
    return this.searchNode(node.left, value);
  } else if (value > node.value) {
    return this.searchNode(node.right, value);
  } else {
    return node;
  }
}
search(value) {
  if (this.root === null) {
    return undefined;
  }
  return this.searchNode(this.root, value);
}

Comparto mi solución del search(value):

    search(value) {
        let currentNode = this.root;
        let found = false;
        while(currentNode !== null && found == false) {
            if(value == currentNode.value) {
                found = true;
            } else if(value < currentNode.value) {
                currentNode = currentNode.left;
            } else {
                currentNode = currentNode.right;
            }
        }
        if(found) {
            return currentNode;
        }
        return undefined;
    }
<code>
    public search(nodeValue : number) : TreeNode | null{
        if(this.root){
            if(nodeValue > this.root.value){
                console.error("node value cannot be bigger than tree.root")
                return null
            }else{
                let currentNode : TreeNode | null = this.root
                while(currentNode){
                    if(currentNode.value === nodeValue){
                        return currentNode
                    }
                    else if(nodeValue < currentNode.value){
                        currentNode = currentNode.left
                    }
                    else if(nodeValue > currentNode.value){
                        currentNode = currentNode.right
                    }
                }
                console.error("there are no nodes with that value")
                return null
            }            
        }else{
            console.error("tree has no root")
            return null
        }
    }

my search 😃 :

 search(value)
    {
        let isFound = false;
        let currentNode = this.root;
        while(currentNode !== null && !isFound)
        {
            if(currentNode.value === value)
            {
                isFound == true;
                return currentNode;
            }
            if( value > currentNode.value )
            {
                currentNode = currentNode.rigth;
            }
            else
            {
                currentNode = currentNode.left;
            }
        }
    }

Mi solución:

    search(value) {
        let currentNode = this.root;
        while(true) {
            if (!currentNode) {
                return "Not Found"
            } else {
                if (value === currentNode.value) {
                    return currentNode;
                } else if (value < currentNode.value) {
                    currentNode = currentNode.left;
                } else {
                    currentNode = currentNode.right;
                }
            }
        }
    }

Acá mi versión con recursividad, me gusta más por ser más limpio de leer, pero puede que más complicado de entender, no sé que ustedes piensen al respecto.

class Node {
    constructor(value) {
        this.value = value;
        this.right = null;
        this.left = null;
    }
}


class BinaryTree {
    constructor() {
        this.root = null;
    }

    search(value, tree = this.root) {

        if (tree == null || value == null) {
            return false; //El elemento no encontrado"
        } 
        
        if (value > tree.value) {
            return this.search(value, tree.right);
        }
        
        if (value < tree.value) {
            return this.search(value, tree.left);
        } 
        
        return true; //El elemento encontrado
    }


    insert(value, tree = this.root) {

        const node = new Node(value);

        if (!this.root) {
            this.root = node;
            return this;
        }

        if (tree.value === node.value) {
            console.error(`${node.value} is Duplicated`);
            return;
        }

        if (node.value < tree.value) {
            if (!tree.left) {
                tree.left = node;
                return this.root;
            }
            this.insert(value, tree.left);

        } else {
            if (!tree.right) {
                tree.right = node;
                return this.root;
            }
            this.insert(value, tree.right)
        }
    }
}

const tree = new BinaryTree();
tree.insert(50);

Search Node Code

  search(value) {
    if (this.root === null) {
      throw new Error("Tree is empty");
    }
    let currentNode = this.root;
      while ( true ) {
        if (!currentNode) {
          throw new Error("Node not found");
        }
        if (value === currentNode.value) {
          return currentNode;
        }
        if (value < currentNode.value) {
          currentNode = currentNode.left;
        } else {
          currentNode = currentNode.right;
        }
      }
  }

Estaría bueno validar que el value no sea igual al valor de un root mediante un condicional que te impida agregar ese valor

search(value){
    let currentNode = this.root;
    while(true){
        if(value == currentNode.value){
            return currentNode;
        }else{
            if(value > currentNode.value){
                if(currentNode.right){
                    currentNode = currentNode.right;
                }else{
                    return currentNode; // si no se encuentra retorna el mas cercano;
                }
            }else{
                if(currentNode.left){
                    currentNode = currentNode.left;
                }else{
                    return currentNode; // si no se encuentra retorna el mas cercano;
                }
            }
        }
    }
}

nodo con el valor 10, debería de estar al lado derecho y abajo del nodo 9

Comparto mi search:

search(value){  
        let current=this.root;
        if(value===this.root.value){
            return this.root;
        }
        else{
            while(current.value!=value){
                if(value < current.value){
                if(value==current.left){
                    //return current.left;
                }
                current=current.left;
            }
            else{
                if(value===current.right){
                   // return current.right;
                }
                current=current.right;
            }
        }
        return current
        }
    }

Esta fue mi solución usando recursividad

    search(value, node = this.root) {
        if (node === null)
            return false;

        if (node.value === value)
            return true;

        const left = this.search(value, node.left)
        const right = this.search(value, node.right)
        return left || right;
    }

Creé esta función que sirve para imprimir los valores del arbol en orden de menor a mayor. Puede ser útil para debuggear, aunque no sea lo recomendable, o simplemente para ver de manera visual el proceso

    printTree(node) {
        if (node === undefined)
            return
        this.printTree(node.left);
        console.log(node.value);
        this.printTree(node.right);
    }

Mi arbol todavía no está terminado, pero mi código se ve así. Los arboles son estructuras de datos optimizadas para ser usadas con recursión; por tanto, funciones recursivas siempre quedarán más cortas y fáciles de leer en estos casos.

class BinarySearchTree {
    constructor() {
        this.root = null;
    }

    insert(value) {
        const newNode = new Node(value);
        if (this.root === null) {
            this.root = newNode;
            return;
        }

        let parentNode = this.getParentFor(value, this.root);
        if (value < parentNode.value)
            parentNode.left = newNode;
        else
            parentNode.right = newNode;
    }   
    
    getParentFor(value, node) {
        if (value < node.value && node.left !== null)
            return this.getParentFor(value, node.left)
        if (value > node.value && node.right !== null)
            return this.getParentFor(value, node.right)

        return node;
    }

    printTree(node = this.root) {
        if (node === null)
            return
        this.printTree(node.left);
        console.log(node.value);
        this.printTree(node.right);
    }
}

search(value, node = this.root) {
    if (value === node.value) {
      return node;
    } else if (value > node.value) {
      return this.search(value, node.right);
    } else {
      return this.search(value, node.left);
    }
  }

search(value){
if(this.root === null) {
console.log(‘error’);
}else {
let currentNode = this.root;
while(true){
if(value !== currentNode.value) {
if(value < currentNode.value){
if(!currentNode.left) {
return false;
}
currentNode = currentNode.left;
} else {
if(!currentNode.right) {
return false;
}
currentNode = currentNode.right;
}
} else {
return currentNode;
}
}

    }
}

Así fue como implementé el método search:

    search(value){
        let currentNode = this.root;

        while(true){
            if(currentNode.value === value){
                return currentNode;
            }else if(value < currentNode.value){
                if(currentNode.left){
                    currentNode = currentNode.left;
                }else{
                    return null;
                }
            }else if(value > currentNode.value){
                if(currentNode.right){
                    currentNode = currentNode.right;
                }else{
                    return null;
                }
            }
        }
    }

Este sería mi método, si en vez de retornar el nodo, quieres retornar un Booleano entonces cambia la sentencia { return currentNode } por { return true }

search(value){
        let currentNode = this.root;
        
        while(currentNode && currentNode.value != value){
            if (value<currentNode.value){
                currentNode=currentNode.left;
            } else if(value > currentNode.value){
                currentNode=currentNode.rigth;
            } 
            if(!currentNode){
                return false;
            } else if(currentNode.value == value){
                return currentNode;
            }
        }
    }

Mi aporte de Search, si yo se que esta enorme jajaj

search(value){

    if(this.root === null){
        return "Tree vacio";
    }else{
        let currentnodet = this.root;
        while(true){
            if(value === currentnodet.value){
                return currentnodet;
            }
            
            if(value < currentnodet.value){
                if(!currentnodet.left){
                    return "No existe el Nodo";
                }else if(value === currentnodet.left.value){
                    return currentnodet.left;
                }else{
                    currentnodet =  currentnodet.left;
                }
            }else{
                if(!currentnodet.right){
                    return "No existe el Nodo";
                }else if(value === currentnodet.right.value){
                    return currentnodet.right;
                }else{
                    currentnodet =  currentnodet.right;
                }
                }
            }
        }
    }

Mi aporte de search y delete

class Node {
    constructor(value){
        this.left =  null
        this.right = null
        this.value = value
    }
}

class BinarySearchTree {
    constructor(){
        this.root = null
    }
    insert(value){
        const newNode = new Node(value)
        if(this.root === null){
            this.root = newNode
            return this
        } else {
            let currentNode = this.root
            while(true) {
                if(value < currentNode.value){
                    if (currentNode.left) {
                        currentNode = currentNode.left
                    } else {
                        currentNode.left = newNode
                        return this
                    }
                } else {
                    if(currentNode.right) {
                        currentNode = currentNode.right
                    } else {
                        currentNode.right = newNode
                        return this
                    }
                }
            }
        }
    }
    search(value, tree = this.root) {
        if(tree === null) {
            return false
        }
        if(value > tree.value) {
            return this.search(value, tree.right)
        }
        if(value < tree.value) {
            return this.search(value, tree.left)
        }
        return true
    }
    min(tree = this.root){
        let current = tree 
        while (current && current.left){
            current = current.left
        }
        return current
    }
    delete(value, tree = this.root){
        // If the value does not exist
        if(tree === null) {
            return undefined
        }
        // If the value is greater than the current tree value we got to right side
        else if(value > tree.value) {
            return this.delete(value, tree.right)
        }
        // If the value is lesser than the current tree value we got to left side
        else if(value < tree.value) {
            return this.delete(value, tree.left)
        } else {
            // if the node does not have child just set null
            if (tree.left === null && tree.right === null) {
                tree.value = null
            } 
            // if the node only have one child place the child in the current node
            else if(tree.left === null) {
                tree = tree.right
                this.delete(tree.value, tree.right)
            } else if (tree.right === null) {
                tree = tree.left
                this.delete(tree.value, tree.left)
            // if the node have two children we must look for the smallest in the 
            // right side node (in order successor) place that value in the current
            // node and then delete the in order successor node
            } else {
                let inOrdSuccesorNode = this.min(tree.right)
                tree.value = inOrdSuccesorNode.value
                this.delete(tree.value, tree.right) 
            }
        }
        return this
    }
}

const tree =  new BinarySearchTree()

¡Lo logre!

search(value){
        if(this.root.value == value){
            return this.root;
        }else{
            let currentNode = this.root;
            while(true){
                if(value < currentNode.value){
                    if(currentNode.left){
                        if(value == currentNode.left.value){
                            return currentNode.left;
                        }else{
                            currentNode = currentNode.left;
                        }
                    }else{
                        return false;
                    }
                }else{
                    if(currentNode.right){
                        if(value == currentNode.right.value){
                            return currentNode.right;
                        }else{
                            currentNode = currentNode.right;
                        }
                    }else{
                        return false;
                    }
                }
            }
        }
    }

Aca les dejo mi código para el método search:

search(value) {
    const searchVal = value;
    if (searchVal === this.root.value) {
      return this.root;
    } else {
      let currentNode = this.root;
      while(true) {
        if (searchVal < currentNode.value) {
          if (currentNode.left === null) return "the searched element doesn't exist"
          if (searchVal === currentNode.left.value) {
            return currentNode.left
          }
          currentNode = currentNode.left
        } else {
          if (currentNode.right === null) return "the searched element doesn't exist"
          if (searchVal === currentNode.right.value) {
            return currentNode.right
          }
          currentNode = currentNode.right
        }
      }
    }
  }

Demostración
Este es el árbol
Buscando 8 Retorna el nodo

Buscando 20 Retorna el nodo y todas sus ramificaciones

Buscando 1 Indica que el valor no esta en el árbol

Este es el código

Extendí un poco más los métodos para obtener más datos en el “search” y creé el método “delete” y un auxiliar “lastLeft” para reubicar ramas cuando se eliminan nodos padres/ramas:

search(value) {
  if (!this.root) { // Si no hay root no hay elementos que buscar
    return null
  }
  let currentNode = this.root
  let parentNode = null // El parentNode es un puntero al padre del nodo buscado y se usará para el método "delete"
  let sonSide = '' // El sonSide es el indicador de cual hijo/lado el nodo buscado es.  También se usará para el método "delete"
  let level = 1 // Valor cosmético para saber en que nivel se encuentra el nodo buscado
  while (true) {
    if (value === currentNode.value) { // Si el valor del currentNodo es el que se está buscando, entonces devuelvo un objeto con: el currentNode, el parentNode, el sonSide y el nivel
      return {node: currentNode, parent: parentNode,sonSide, level}
    } else {
      if (value < currentNode.value) { // Si el valor es menor al valor del currentNode hay que saber si tiene nodo del lado izquierdo.  Si no los tiene entonces el valor buscado no existirá en el árbol, por lo tanto no fue encontrado y devolvemos "null"
        if (currentNode.left) { // Si sí tiene nodo del lado izquierdo entonces reasigna el valor del currentNode, pero antes actualiza el valor del parentNode, del sonSide y del level
          parentNode = currentNode
          sonSide = 'left'
          currentNode = currentNode.left
          level++
        } else {
          return null
        }
      } else { // Si el valor no es menor que el valor del currentNode entonces hacemos un recorrido similar, pero con el lado derecho.
        if (currentNode.right) { // Para continuar, debe tener un nodo derecho, sino el valor no existe.
          parentNode = currentNode
          sonSide = 'right'
          currentNode = currentNode.right
          level++
        } else {
          return null
        }
      }
    }
  }
}
lastLeft(node) { // Método auxiliar para saber cuál es el nodo en el extremo izquierdo de un nodo específico.
  let last = node
  if (node) {
    while (last.left) {
      last = last.left
    }
  }
  return last
}
delete(value) { // Este método debe considerar varios escenarios:
  // A- Que el nodo sea una hoja (sin left ni right)
  // B- Que el nodo sea una rama con uno o dos lados.
  // C- Que el nodo sea el root
  // Para cada escenario debemos realizar 3 acciones:
  // 1- Revisar que el nodo a eliminar exista y conocer quien es su padre y el lado al cual pertenece. (para esto nos ayudaremos del método "search")
  // 2- Si el nodo tiene ramas u hojas, hay que moverlas (reasignar el puntero) al otro lado.  Para esto vamos a definir la estrategia de favorecer al lado derecho, es decir, vamos a mover toda la estructura de nodos del lado izquierdo al extremo izquierdo del nodo derecho.  Esto porque el nodo en el extremo izquierdo del lado derecho contiene un valor superior al valor del lado izquierdo del nodo que queremos eliminar.
  // 3- Si el nodo a eliminar es el root, entonces reasignamos el root para que apunte al lado derecho (porque anteriormente trasladamos todo el lado izquierdo al extremo izquierdo del lado derecho).  Y si el nodo a eliminar no es el root, entonces simplemente le decimos al padre que reasigne su hijo para apuntar al lado derecho del nodo que queremos eliminar (la información de quien es el padre y de cuál lado el hijo es, la obtuvimos en la búsqueda inicial con el método "search").
  let nodeToDelete = this.search(value)
  if (nodeToDelete) {
    if (nodeToDelete.node.right) {
      const lastLeft = this.lastLeft(nodeToDelete.node.right)
      lastLeft.left = nodeToDelete.node.left
    } else { // Importante:  Si el nodo a eliminar no tiene nodos del lado derecho, debemos mover todos los nodos del lado izquierdo al derecho para que cuando se reasignen estos nodos correctamente al padre (al padre siempre se le reasignaran los nodos del lado derecho del nodo a eliminar). 
      nodeToDelete.node.right = nodeToDelete.node.left
    }
    if (nodeToDelete.node === this.root) {
      this.root = nodeToDelete.node.right
    } else {
      if (nodeToDelete.sonSide == 'left') {
        nodeToDelete.parent.left = nodeToDelete.node.right
      } else {
        nodeToDelete.parent.right = nodeToDelete.node.right
      }
    }          
    return this
  } else {
    return null
  }
}

El nodo 10 está mal. Debería ser mayor a 33 y menor a 101, como el 42 por ejemplo

Mi solución al desafío del search:

search(value){
        if(this.tree === null){
            return "No tree inserts found"
        }
        if(value === this.root.value){
            return this.root
        }
        let currentNode = this.root
        while(true){
            if(value < currentNode.value){
                if(currentNode.left){
                    if(currentNode.left.value === value){
                        return currentNode.left
                    }
                } else if(currentNode.right === null){
                    return "Your search found no matches"
                }
                currentNode = currentNode.left
            } else {
                if(currentNode.right){
                    if(currentNode.right.value === value){
                        return currentNode.right
                    }
                } else if(currentNode.right === null){
                    return "Your search found no matches"
                }
                currentNode = currentNode.right
            }
        }
    }

Me parece que Diego de Granda (alias “El profe”) se olvidó de incluir la solución al desafío en los recursos de la clase o puede ser que no busqué bien.

Aqui hay una forma de hacer un search y un print sin usar el while.

export class Node {
  constructor(value) {
    this.left = null;
    this.right = null;
    this.value = value;
  }
  printNode() {
    console.log(this.value);
    if (this.left) this.left.printNode();
    if (this.right) this.right.printNode();
  }

  search(value) {
    if (this.value === value) return this;

    if (value < this.value && this.left) return this.left.search(value);

    return this.right ? this.right.search(value) : null;
  }
}

export class BinarySearchTree {
  constructor() {
    this.root = null;
  }

  print() {
    this.root.printNode();
  }

  search(value, node = this.root) {
    return node.search(value);
  }

  insert(value) {
    const newNode = new Node(value);

    if (this.root === null) {
      this.root = newNode;
    } else {
      let currentNode = this.root;
      while (true) {
        if (value < currentNode.value) {
          if (!currentNode.left) {
            currentNode.left = newNode;
            return this;
          }
          currentNode = currentNode.left;
        } else {
          if (!currentNode.right) {
            currentNode.right = newNode;
            return this;
          }
          currentNode = currentNode.right;
        }
      }
    }
  }
}

El 10 no respetó la regla, debió ser agregado como subdivición en 9 del lado derecho (eso es lo que pensé)

Hola, les dejo mi solución usando recursividad y destructuring de las funciones para tener un manejo de los parámetros más optimo. 😅

search({ value , branch = this.root , branchValue = this.root.value })
  {
    const currentValue = branch.value
    if(value === branch.value)
    {
      return {
        valueToFind : value,
        branchOfTheValue : branch
      }
    }

    if(value > branchValue)
    {
      console.log("Right");
      return this.search({ value : value, branch : branch.right , branchValue : currentValue })
    }
    else if (value < branchValue)
    {
      console.log("Left");
      return this.search({ value : value , branch : branch.left , branchValue : currentValue })
    }  
  }

Método Search!

    search(value) {
        let currentNode = this.root;

        return this.#search_recursive(currentNode, value);
    }
    #search_recursive(currentNode, value) {
        if (value != currentNode.value) {
            if (value > currentNode.value) {
                if (currentNode.right) {
                    return this.#search_recursive(currentNode.right, value);
                }
            } else {
                if (currentNode.left) {
                    return this.#search_recursive(currentNode.left, value);
                }
            }
        } else {
            return currentNode;
        }
    }

Clase tree desarrollada antes de ver el script del curso, solo tiene el método insert. Tiene un parámetro adicional que muestra el largo o los niveles del árbol:

class Node {
    constructor(value) {
        this.left = null;
        this.right = null;
        this.value = value;
    }
}

class Tree {
    constructor() {
        this.root = null;
        this.length = 0;
    }
    insert(value) {
        const newNode = new Node(value);
        debugger;
        let levels = 1;

        if (this.length === 0) {
            this.root = newNode;
            this.length++;
        } else {
            let parent = this.root;

            while (true) {
                if (value != parent.value) {
                    if (value > parent.value) {
                        if (!parent.right) {
                            parent.right = newNode;
                            if (levels >= this.length) { this.length++; };
                            break;
                        } else {
                            parent = parent.right;
                            levels++;
                        }
                    } else {
                        if (!parent.left) {
                            parent.left = newNode;
                            if (levels >= this.length) { this.length++; };
                            break;
                        } else {
                            parent = parent.left;
                            levels++;
                        }
                    }
                } else {
                    break;
                }
            }
        }

        return this;
    }
}

let myTree = new Tree();

El valor de la rama derecha del subarbol 33, no es menor, por lo tanto el arbol no está balanceado.

Yo dudando de mi mismo, y teniendo sindrome del impostor

Diego: Yo sé que ya lo sabes, no tengas miedo y cree en tí.

Gracias!

Que tal buen dia. agregando el metodo remove(), search()… increible… un poco de investigacion logre implementarlos y entendiendo la logica, si asi es.


class Node {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
  }
}

class BinarySearchTree {
  constructor() {
    this.root = null;
  }
  insert(value) {
    const newNode = new Node(value);
    if (this.root === null) {
      this.root = newNode;
      return this;
    } else {
      let currentNode = this.root;
      while(true) {
        if (value === currentNode.value) return undefined;
        if (value < currentNode.value) {
          //validamos si no existe un nodo en el lado izquierdo, entoces se agrega en esa posicion
          if (!currentNode.left) {
            currentNode.left = newNode;
            return this;
          }
          currentNode = currentNode.left;
        } else {
          if (!currentNode.right) {
            currentNode.right = newNode;
            return this;            
          }
          currentNode = currentNode.right;
        }
      }
    }
  }
  search(value) {
    let message = {Error: 'No node in the search tree'}
    if(!this.root) throw new Error(message.Error);
    let currentNode = this.root;
    let found = false;
    while(currentNode && !found) {
      if (value < currentNode.value) {
        currentNode = currentNode.left;
      } else if (value > currentNode.value) {
        currentNode = currentNode.right;
      } else {
        found = currentNode;
      }
    }
    if (!found) return `No value exists`;
    return found;
  }
  remove(value) {
    const removeNode = (node, value) => {
      if (!node) {
        return null;
      }
      if (value == node.value) {
        if (!node.left && !node.right) {
          return null;
        }
        if (!node.left) {
          return node.right;
        }
        if (!node.right) {
          return node.left;
        }
        let temp = node.right;
        let parent = null;

        while (temp) {
          if (!temp.left) {
            break;
          }
          parent = temp;
          temp = temp.left;
        }
        node.value = temp.value;
        if (!parent) {
          node.right = temp.right;
        } else if (!parent.left.right) {
          parent.left = null;
        } else {
          parent.left = temp.right
        }
      } else if (value < node.value){
        node.left = removeNode(node.left, value);
        return node;
      } 
      node.right = removeNode(node.right, value);
      return node;
    }
    this.root = removeNode(this.root, value);
  }
}

const myTree = new BinarySearchTree();

Solucion al reto

search(value){
        let currentNode = this.root;
        while (true) {
            if(value < currentNode.value){
               currentNode = currentNode.left;
               if(currentNode === null){
                    return console.log('no se encontro el elemento');
                }
               if(value == currentNode.value){
                   return currentNode;
               }
           }else if(value > currentNode.value){
               currentNode = currentNode.rigth;
               if(currentNode === null){
                    return console.log('no se encontro el elemento');
               }
               if(value == currentNode.value){
                    return currentNode;
                }
           }else{
               return currentNode;
           }
       }
    }

Este me funciona muy bien!

search(value) {
    if(value === this.root.value) { // Si el valor está en el root
        return this.root;
    } else { // No está en el root
        let currentNode = this.root;
        while (true) {
            if (value < currentNode.value) { // Buscamos a la izquierda
                if (currentNode.left === null) {
                    console.log('No existe el número');
                    return;
                } else {
                    if (currentNode.left.value === value) {
                        return currentNode.left;
                    } else {
                        currentNode = currentNode.left;
                    }
                }
            } else { // Buscamos a la derecha
                if (currentNode.right === null) {
                    console.log('No existe el número');
                    return;
                } else {
                    if (currentNode.right.value === value) {
                        return currentNode.right;
                    } else {
                        currentNode = currentNode.right;
                    }
                }
            }
        }
    }
}

He aquí mi aproximación al search:

search(value){
    if(this.root === null){
      return null;
    }
    let currentNode = this.root;
    while(true){
      if(currentNode.value === value){
        return currentNode;
      }
      if(value < currentNode.value){
        if(currentNode.left === null){
          return null;
        }
        currentNode = currentNode.left;
      }else{
        if(currentNode.right === null){
          return null;
        }
        currentNode = currentNode.right;
      }
    }
  }

Cuando vas comprendiendo qué hacer y cómo aplicar los métodos a medida que se está explicando, sale a relucir que el profe es excelente.

Termine el reto para el método search 😄

    searchLeftNRight(value, currentNode) {
        //Validaciones si los valores son iguales
        
        if(currentNode.right !== null){
            if(currentNode.right.value === value){
                // console.log("El nodo fue encontrado es: ")
                return currentNode.right
            }
        }

        if(currentNode.left !== null){
            if(currentNode.left.value === value){
                // console.log("El nodo fue encontrado es: ")
                return currentNode.left
            }
        }
        //Si ya no hay valores hijos en los que buscar
        if(currentNode.right === null & currentNode.left === null){
            return undefined
        }

        const newNodeToSearchLeft = currentNode.left
        const newNodeToSearchRight = currentNode.right
        const searchValue = value

        //Buscando en los nodos hijos con recursividad
        if(newNodeToSearchLeft){
            if(this.searchLeftNRight(searchValue, newNodeToSearchLeft) !== undefined){
                return this.searchLeftNRight(searchValue, newNodeToSearchLeft)
            }
        }

        if(newNodeToSearchRight){
            if(this.searchLeftNRight(searchValue, newNodeToSearchRight) !== undefined){
                return this.searchLeftNRight(searchValue, newNodeToSearchRight)    
            }
        }
    }
    search(value){
        if(this.root.value === value){
            return this.root
        }else{
            const currentNode = this.root
            if(this.searchLeftNRight(value, currentNode) !== undefined){
                return this.searchLeftNRight(value, currentNode)
            }else{
                console.error("El valor no fue encontrado en el árbol")
            }
        }
    }

Mi solución al reto 😜

search(value) {
  if (!this.root) return `value:${value} not found`;
  let currentNode = this.root;
  while (true) {
    if (value === currentNode.value) {
      break;
    } else {
      if (value < currentNode.value) {
        if (!currentNode.left) return `value:${value} not found`;
        currentNode = currentNode.left;
      } else {
        if (!currentNode.right) return `value:${value} not found`;
        currentNode = currentNode.right;
      }
    }
  }
  return currentNode;
}

Mi versión del método search.

  • Con Recursividad:
search(value, tree = this.root) {
    if(!this.root)  return console.error("The Binary Search Tree is empty");
    if(!tree) return console.error("The node is not in the tree");

    if (value < tree.value) {
      return this.search(value, tree.left);
    } else if (value > tree.value) {
      return this.search(value, tree.rigth);
    } else {
      console.log("The value has been finded in the Tree");
      return tree;
    }
  }

Al usar Recursividad para hacer una búsqueda, puede haber el problema de que ocurra un StackOverflow al superar las 1000 peticiones

  • Usando While
search(value) {
    if(!this.root)  return console.error("The Binary Search Tree is empty");

    let treeNode = this.root;
    while (treeNode) {
      if (value < treeNode.value) {
        treeNode = treeNode.left;
      } else if (value > treeNode.value) {
        treeNode = treeNode.rigth;
      } else {
        console.log("The value has been finded in the Tree");
        return treeNode;
      }
    }
    if(!treeNode) return console.error("The node is not in the tree");
  }

Aquí comparto el método searchque hice por si a alguien le interesa.

search(value){
        let currentNode = this.root;

        while (true) {
            if (value === currentNode.value) {
                return currentNode;
            } else {
                if (value < currentNode.value) {
                    currentNode = currentNode.left;
                } else {
                    currentNode = currentNode.right;
                }
            }
        }
    }

Mi método delete, es parecido al método search pero con algunas diferencias importantes

delete(value){
        if(!this.root){
            return this.root;
        }else{
            let pointer = this.root;
        while(true){
            if (pointer.left && pointer.left.value ===  value) {
                pointer.left = null;
                return this;
            }else if(pointer.right && pointer.right.value ===  value){
                pointer.right = null;
                return this;
            }else if(value < pointer.value && pointer.left){
                pointer = pointer.left;
                continue;
            }else if(pointer.right){
                pointer =  pointer.right;
                continue;
            }
            break;
        }
        return "Elemento no encontrado";
        }    
    }

Así me quedó el search:

search(value) {
    if (this.root.value === value) {
      return this.root
    } else {
      let currentNode = this.root

      while (true) {
        if (value < currentNode.value) {
          if (!currentNode.left) {
            console.warn("Node not found")
            return null
          } else if (currentNode.left.value === value) {
            return currentNode.left
          } else {
            currentNode = currentNode.left
          }
        } else {
          if (!currentNode.right) {
            console.warn("Node not found")
            return null
          } else if (currentNode.right.value === value) {
            return currentNode.right
          } else {
            currentNode = currentNode.right
          }
        }
      }
    }
  }

Buenas a todos! Espero que esten disfrutando este curso tanto como yo, seguro coinciden en que el profe Diego explica muy bien.
Aca les dejo mi codigo aplicado con recursividad ya que creo que es uno de los pocos casos en los que me resulta util y mucho más facil de entender, a pesar de quizás la desventaja algorítmica que pueda llegar a tener.

// 
class Node {
    constructor(value){
        this.value = value;
        this.left = null;
        this.right = null;
    }
}
class BinarySearchTree {
    constructor(){
        this.root = null;
        return this;
    }
    add(value, currentNode = this.root){
        let newNode = new Node(value);
        if(!this.root){
            this.root = newNode;
            return this.root;
        }
        if(value > currentNode.value){
            if(!currentNode.right){
                currentNode.right = newNode;
                return this.root;
            }
            return this.add(value, currentNode.right)
        }else{
            if(!currentNode.left){
                currentNode.left = newNode;
                return this.root;
            }
            return this.add(value, currentNode.left)
        }
    }
    isThere(value, currentNode = this.root){
        if(!currentNode){
            return false;
        }
        if(value === currentNode.value){
            return true;
        }
        if(value > currentNode.value){
            return this.isThere(value, currentNode.right)
        }else{
            return this.isThere(value, currentNode.left)
        }
    }
}

Mi solución para el método search:

    search(value) {
        if (this.root === null) {
            return 'There are not items in the tree.';
        } else {
            let currentNode = this.root;

            while(true) {
                if (value <= currentNode.value) {

                    if (!currentNode.left) {
                        return 'Value is not exist in the tree.';
                    }

                    if (currentNode.value === value) {
                        return currentNode;
                    }

                    currentNode = currentNode.left;

                } else {

                    if (!currentNode.right) {
                        return 'Value is not exist in the tree.';
                    }

                    if (currentNode.value === value) {
                        return currentNode;
                    } 

                    currentNode = currentNode.right;
                }
            }
        }        
    }
class Node {
  constructor(value) {
    this.value = value;
    this.r = null;
    this.l = null;
  }
}

class BST {
  constructor() {
    this.root = null;
    this.len = 0;
  }

  insert(val) {
    const node = new Node(val);
    if (!this.root) {
      this.root = node;
    } else {
      let current = this.root;
      while (true) {
        if (val > current.value) {
          if (!current.r) {
            current.r = node;
          }
          current = current.r;
        } else if (val < current.value) {
          if (!current.l) {
            current.l = node;
          }
          current = current.l;
        } else {
          break;
        }
      }
    }
    this.len++;
  }

  search(val) {
    let current = this.root;
    let result = false;
    let i = 0;
    while (true) {
      i++;
      if(val == current.value){
        result = true;
        break;
      }else if (val > current.value) {
        if (!current.r) {
          break;
        }
        current = current.r;
      } else if (val < current.value) {
        if (!current.l) {
          break;
        }
        current = current.l;
      }
    }
    return {result, i};
  }
}

const t = new BST();
t.insert(10);
t.insert(4);
t.insert(20);
t.insert(2);
t.insert(8);
t.insert(17);
t.insert(170);
console.log(t)
console.log(t.search(17));

Les comparto mi implementación usando recursividad y JSDocs:

class Node {
  constructor(value) {
    /** 
     * @type {Node}
     * @public
     */
    this.left = null
    /** 
     * @type {Node}
     * @public
     */
    this.right = null
    /**
     * @type {Number}
     * @public
     */
    this.value = value
  }
}

class BinarySearchTree {
  constructor() {
    /**
     * @type {Node}
     * @public
     */
    this.root = null
  }

  /**
   * @param {Number} value 
   * @param {Node} root 
   */
  insert(value, root = this.root) {
    if (!this.root) {
      this.root = new Node(value)

      return
    }

    if (value > root.value) {
      if (root.right) this.insert(value, root.right)
      else root.right = new Node(value)
    } else {
      if (root.left) this.insert(value, root.left)
      else root.left = new Node(value)
    }
  }

  /**
   * @param {Number} value 
   * @param {Node} root 
   * @returns {Node} found node
   * @throws an error if the tree is empty or if the value wasn't found
   */
  search(value, root = this.root) {
    if (!this.root) throw new Error('The tree does not contain nodes')
    if (!root) throw new Error('Node not found')

    if (value === root.value) return root

    if (value <= root.value) return this.search(value, root.left)

    return this.search(value, root.right)
  }
}

Mi solución 😃

 search(value) {
    let currentNode = this.root;
    while (true) {
      if (value === currentNode.value) {
        return currentNode;
      }
      if (value < currentNode.value && currentNode.left) {
        currentNode = currentNode.left;
      } else if (currentNode.right) {
        currentNode = currentNode.right;
      } else {
        return 'value not found';
      }
    }
  }

Aqui esta el reto

class Node {
    constructor(value){
        this.left = null
        this.right = null
        this.value = value
    }
}

class BinarySearchTree {
    constructor(){
        this.root = null
    }

    search(value){
        if(this.root === null){
            console.log('error, no existe ningun nodo en el tree')
            return 'error, no existe ningun nodo en el tree'
        }
        else{
            let currentNode = this.root
            while(true){
                if(currentNode.value === value){
                    return currentNode
                }
                if(currentNode.value > value){
                    if(!currentNode.left){
                        console.log('El valor no existe en el tree')
                        return 'El valor no existe en el tree'
                    }
                    currentNode = currentNode.left
                }
                else{
                    if(!currentNode.right){
                        console.log('El valor no existe en el tree')
                        return 'El valor no existe en el tree'
                    }
                    currentNode = currentNode.right
                }
            }
        }
    }

    insert(value){
        const newNode = new Node(value)
        if(this.root === null){
            this.root = newNode;
        }
        else{
            let currentNode = this.root
            let nextNode = this.root
            while(nextNode !== null){
                currentNode = nextNode
                if(currentNode.value > value){
                    nextNode = currentNode.left
                }
                else{
                    nextNode = currentNode.right
                }
            }
            if(currentNode.value > value){
                currentNode.left = newNode
            }
            else{
                currentNode.right = newNode
            }
        }
    }
    
    insertPlazi(value){
        const newNode = new Node(value)
        if(this.root === null){
            this.root = newNode;
        }
        else{
            let currentNode = this.root
           
            while(true){
                currentNode = nextNode
                if(currentNode.value > value){
                    if(!currentNode.left){
                        currentNode.left = newNode
                        return this;
                    }
                    currentNode = currentNode.left
                }
                else{
                    if(!currentNode.right){
                        currentNode.right = newNode
                        return this;
                    }
                    currentNode = currentNode.right
                }
            }
        }
    }
}

const tree = new BinarySearchTree()
class Node {
    constructor(value){
        this.left = null
        this.right = null
        this.value = value
    }
}

class BinarySearchTree {
    constructor(){
        this.root = null
    }

    insert(value){
        const newNode = new Node(value)
        if(this.root === null){
            this.root = newNode;
        }
        else{
            let currentNode = this.root
            let nextNode = this.root
            while(nextNode !== null){
                currentNode = nextNode
                if(currentNode.value > value){
                    nextNode = currentNode.left
                }
                else{
                    nextNode = currentNode.right
                }
            }
            if(currentNode.value > value){
                currentNode.left = newNode
            }
            else{
                currentNode.right = newNode
            }
        }
    }
}

const tree = new BinarySearchTree()

cual seria la logica del delete

Mi implementación del método search 😄

search(value) {
    let currentNode = this.root;
    while (true) {
        if (value > currentNode.value) {
            if (currentNode.right) {
                if (currentNode.right.value === value) {
                    return currentNode.right;
                }
                currentNode = currentNode.right;
            } else return null;
        } else {
            if (currentNode.left) {
                if (currentNode.left.value === value) {
                    return currentNode.left;
                }
                currentNode = currentNode.left;
            }
        }
    }
}

Lo logré🥺

 seach(value) {
        let currentNode = this.root;
        while(currentNode.value !== value) {
            if(value < currentNode.value) {
                currentNode = currentNode.left;
                if(value === currentNode.value) {
                    return currentNode;
                }
            } else {
                currentNode = currentNode.right;
                if(value === currentNode.value) {
                    return currentNode;
                }
            }
        }
        return this
    }
  search(value) {
    if (!this.root) {
      return null;
    } else {
      let currentNode = this.root;
      while (true) {
        if (currentNode.value === value) {
          return currentNode;
        }
        if (value <= currentNode.value) {
          if (currentNode.left) {
            currentNode = currentNode.left;
          } else {
            return null;
          }
        } else {
          if (currentNode.right) {
            currentNode = currentNode.right;
          } else {
            return null;
          }
        }
      }
    }
  }

Así quedó mi search()

    search(value){
        let currentNode = this.root;
        while(true){
            if(value === currentNode.value){
                return currentNode
            }else{
                if (value < currentNode.value){
                    if (currentNode.left !== null){
                        currentNode = currentNode.left;
                    }else{
                        return undefined;
                    }
                }
                if(value > currentNode.value){
                    if (currentNode.right !== null){
                        currentNode = currentNode.right;
                    }else{
                        return undefined;
                    }
                }
            }
        }
    }

Mi metodo search 😃

    search(value) {
        let currentNode = this.root;
        while (true) {

            if (value === currentNode.value) {
                return currentNode;
            } 

            if (isNaN(currentNode.left) || isNaN(currentNode.right)) {
                return undefined;
            }

            if (value <= currentNode.value  ) {
                currentNode = currentNode.left;
                continue;
            } 

            if (value >= currentNode.value) {
                currentNode = currentNode.right;
                continue;
            }

        }
    }

Les comparto mi solución al reto.

    search(value) {
        if (this.root === null) {
            console.log("Binary tree is empty");
            return false;
        } else {
            let currentNode = this.root;
            while (true) {
                if (value === currentNode.value) {
                    return currentNode;
                }
                else if (value < currentNode.value) {
                    if (!currentNode.left) {
                        console.log("Your value isn't in this tree");
                        return false;
                    }
                    if (value === currentNode.left) {
                        return currentNode.left;
                    }
                    currentNode = currentNode.left;
                } else {
                    if (!currentNode.right) {
                        console.log("Your value isn't in this tree");
                        return false;
                    }
                    if (value === currentNode.right) {
                        return currentNode.right;
                    }
                    currentNode = currentNode.right;
                }
            }
        }
    }

Buenas, compañeros.
Ya tiene unas semanas que tome esta clase, pero antes de pasar a gráfos quería profundizar más en árboles binarios. Les dejo unas recomendaciones para que puedan complementar lo visto en las clases:

También quiero dar un pequeño aporte. Al código que estuvimos escribiendo le agregé el metodo de eliminar nodos dentro del árbol, tanto para nodos sin hijo y nodos con uno o dos hijos.
Espero que las fuentes les ayuden y si tienen algo que complementar o mejorar a mi código, con gusto los leo. ❤️

class Node{
    constructor(value){
        this.left =  null;
        this.right = null;
        this.father = null;
        this.value = value;
    }
}

class BinarySearchTree{
    constructor(){
        this.root = null;
    }

    insert(value){
        //Creamos una instancia del nuevo nodo.
        const newNode = new Node(value);

        //Verificamos si la raiz del arbol tiene hijos
        //en caso de que no tenga, la raiz va apuntar al nodo que acabamos de instanciar.
        if(this.root === null){
            this.root = newNode;
            return this;
        }else{
            //En caso de que la raiz tenga hijos, creamos una variable que apunte a la raiz
            let currentNode = this.root;

            //Entramos en un ciclo "infinito"
            while(true){

                //Varificamos si el valor a insertar es menor al nodo al que estamos apuntado
                //La primera vez que se ejecuta siempre revisa el valor del nodo raiz
                if(value < currentNode.value){

                    //Si el valor es menor verificamos si el nodo izquierdo es null
                    //Si es null el nodo va apuntar al nodo que instanciamos
                    if(currentNode.left === null){
                        newNode.father = currentNode;
                        currentNode.left = newNode;
                        return this;
                    }else{
                        //En caso de que el nodo no sea null:
                        //la variable que apuntaba a raiz empieza a apuntar al nodo izquierdo existente
                        //El ciclo empieza otra vez
                        currentNode = currentNode.left;
                    }
                }else{
                    //En caso de que el valor a insertar sea mayor
                    //Verificamos si el nodo derecho es null
                    //Si es null el nodo va apuntar al nodo que instanciamos
                    if(currentNode.right === null){
                        newNode.father = currentNode;
                        currentNode.right = newNode;
                        return this;
                    }else{
                        //Si no es null 
                        //La variable que apunta a raiz empieza a apuntar al nodo derecho existente
                        //El ciclo empieza otra vez
                        currentNode = currentNode.right;
                    }
                }
            }
        }
    }

    search(value){
        //Verificamos si la raiz es nula, si es nula regresamos null
        if(this.root === null){
            return null;
        }
        //Verificamos si el valor es igual a la raiz, si es igual, regresamos la raiz
        if(value === this.root.value){
            return this.root;
        }else{
            //Si el valor no es igual a la raiz:

            //Creamos una variable que apunte a la raiz
            let currentNode = this.root;

            //Entramos en un ciclo "infinito"
            while(true){
                
                //Verificamos si el nodo al que apuntamos es nulo, si es nulo retornamos null
                if(currentNode === null){
                    return null;
                }
                //Verificamos si el valor es igual al valor del nodo al que apuntamos, si el igual retornamos el nodo
                if(value === currentNode.value){
                    return currentNode;
                }
                //Verificamos si el valor es menor al valor del nodo al que apuntamos
                if(value < currentNode.value){
                    //Si el valor buscado es menor al nodo, currentNode apunta al sub-arbol izquierdo del nodo
                    currentNode = currentNode.left;
                    continue;
                }
                //Verificamos si el valor es mayor al valor del nodo al que apuntamos
                if(value > currentNode.value){
                    //Si el valor buscado es mayor al nodo, currentNode apunta al sub-arbol derecho del nodo
                    currentNode = currentNode.right;
                    continue;
                }
            }
        }
    }

    deleteNode(value){
        if(this.search(value) === null){
            return "El valor no se encuentra dentro del arbol";
        }else{
            let nodeToDelete = this.search(value);
            
            //Si es un nodo hoja
            if (nodeToDelete.left === null && nodeToDelete.right === null){
                let holdingNode = nodeToDelete.father;
                //Verificar si es un nodo derecho o izquierdo
                if(holdingNode.left === nodeToDelete){
                    holdingNode.left = null;
                    return this;
                }else{
                    holdingNode.right = null;
                    return this;
                }
            }

            //Si es un nodo con un hijo
            if(nodeToDelete.left === null){
                let holdingNode = nodeToDelete.father;
                let childNode = nodeToDelete.right;
                childNode.father = holdingNode;
                if(nodeToDelete === holdingNode.left){
                    holdingNode.left = childNode;
                    nodeToDelete.right = null;
                    nodeToDelete.father = null;
                    return this;
                }else{
                    holdingNode.right = childNode;
                    nodeToDelete.right = null;
                    nodeToDelete.father = null;
                    return this;
                }
            }
            if(nodeToDelete.right === null){
                let holdingNode = nodeToDelete.father;
                let childNode = nodeToDelete.left;
                childNode.father = holdingNode;
                if(nodeToDelete === holdingNode.left){
                    holdingNode.left = childNode;
                    nodeToDelete.father = null;
                    nodeToDelete.left = null;
                    return this;
                }else{
                    holdingNode.right = childNode;
                    nodeToDelete.left = null;
                    nodeToDelete.father = null;
                    return this;
                }
            }

            //Si es un nodo con dos hijos
            if(nodeToDelete.left != null && nodeToDelete.right != null){
                //Buscamos el nodo con el menor valor del sub arbol derecho
                let rightTree = nodeToDelete.right;
                // Apuntamos al hijo iquierdo del sub arbol derecho del nodo a eliminar
                let leftNode =  rightTree.left;
                // En un ciclo verificamos si el nodo tiene hijo izquierdo hasta que ya no tenga hijo izquierdo
                while(true){
                    if(leftNode.left === null){
                        // Si no tiene hijo izquierdo 
                        // Su valor se le asigna al nodo al que se le estaba apuntando al principio
                        nodeToDelete.value = leftNode.value;
                        // Verificamos si tiene hijo derecho
                        if(leftNode.right != null){
                            //Si tiene hijo derecho 
                            // Se crea un apuntador al nodo buscado
                            // El padre del nodo, va apuntar al hijo del nodo 
                            leftNode.father.left = leftNode.right;
                            // En el nodo hijo, su padre va a ser el padre del nodo buscado 
                            leftNode.right.father = leftNode.father;
                        }else{
                            leftNode.father.left = null;
                        }
                        // En el nodo buscado, va apuntar a null en hijos y padre
                        leftNode.father = null;
                        leftNode.right = null;
                        leftNode.left = null;
                        return this;
                    }else{
                        // Si tiene un hijo izquierdo apuntamos a ese nodo y se repite el ciclo
                        leftNode = leftNode.left;
                        return this;
                    }
                }
            }
        }
    }
}

let tree = new BinarySearchTree();

    search(value){
        if(this.root == null){
            return `No hay nada en el tree`
        }else{
            let currentNode = this.root
            try{
                while(true){
                    if(value < currentNode.value){
                        if(currentNode.left.value == value){
                            return true
                        }
                        currentNode = currentNode.left
                    }else{
                        console.log(currentNode)
                        if(currentNode.right.value == value){
                            return true
                        }
                        currentNode = currentNode.right
                    }
                }
            }catch{
                return false
            }
        }
    }
}

Así quedó mi búsqueda:

search(value){
  let currentNode = this.root

  while(true){
    if(currentNode === null){
      return null
    }

    if(value === currentNode.value){
      return currentNode
    }

    if(value > currentNode.value){
      currentNode = currentNode.right
    }else{
      currentNode = currentNode.left
    }
  }
}

Aquí está mi aporte, estoy muy orgulloso de haber podido desarrollar la lógica, espero su feedback amigos!😄

search(value) {
    let currentNode = this.root;
    if (value === currentNode.value) {
      return currentNode;
    }
    while (value !== currentNode.value) {
      if (value > currentNode.value) {
        currentNode = currentNode.right;
        if (value === currentNode.value) {
          return currentNode;
        }
      }
      if (value < currentNode.value) {
        currentNode = currentNode.left;
        if (value === currentNode.value) {
          return currentNode;
        }
      }
    }
  }

Aca dejo mi search (Si alguien aporta una linea para que cuando ingrese un value vacio o un espacio se envie un mensaje de error lo comenta, gracias):

    search(value) {
        
        if (this.root === null) return null;

        else if (this.root.value === value) return this.root;
        else {
            let currentNode = this.root;

            while(true) {
                if (currentNode.value < value) {
                    if (currentNode.right.value === value) return currentNode.right;

                    currentNode = currentNode.right;
                } else {
                    if (currentNode.left.value === value) return currentNode.left;

                    currentNode = currentNode.left;
                }
            }
        }
    };

Este es mi aporte, me parece que se le pueden agregar “index” a los items como un valor adicional, así no necesitas conocer el “valor” del nodo, ya que puede que no sea numérico. Así que tomé el “valor” como si fuesen “indexes”

class node {
    constructor(value) {
        this.left = null;
        this.rigth = null;
        this.value = value;
    }
}

class binaryTree {
    constructor() {
        this.root = null;
    }

    insert(value) {
        const newNode = new node(value);

        if(this.root === null) {
            this.root = newNode;
        }
        else {
            let currentNode = this.root;
            while(true) {
                if(value < currentNode.value) {
                    if(!currentNode.left) {
                        currentNode.left = newNode;
                        return this;
                    }
                    currentNode = currentNode.left;
                }
                else {
                    if(!currentNode.rigth) {
                        currentNode.rigth = newNode;
                        return this;
                    }
                    else {
                        currentNode = currentNode.rigth;
                    }
                }
            }
        }
    }

    search(index) {
        if(index === this.root.value) {
            return this.root;
        }
        let temp = this.root;
        while(true) {
            if(index < temp.value) {
                temp =temp.left;
                if(index === temp.value) {
                    return temp;
                }
            }
            else if(index > temp.value) {
                temp = temp.rigth;
                if(index === temp.value) {
                    return temp;
                }
            }
        }
    }
}

const tree = new binaryTree();

tree.insert(10);
tree.insert(4);
tree.insert(20);
tree.insert(2);
tree.insert(8);
tree.insert(17);
tree.insert(170);

console.log(tree);

Reto cumplido!! Las sugerencias de mejora son binevenidas…

search(number) {
        let currentNode = this.root
        while(currentNode.value !== number) {
            if(!currentNode) {
                return "The tree is empty"
            } else {
                if(number < currentNode.value) {
                    if(currentNode.left) {
                        currentNode = currentNode.left
                    } else {
                        return "This number doesnt exist in the tree"
                    }
                } else if(number > currentNode.value) {
                    currentNode = currentNode.right
                } else {
                    return "This number doesnt exist in the tree"
                }
            }
        }
        return currentNode;
    } 
search (value) {
    if (value === this.root.value) {
      return this.root
    } else {
      let currentNode = this.root
      while (true) {
        if (value < currentNode.value) {
          currentNode = currentNode.left
          if (currentNode) {
            if (value === currentNode.value) {
              return currentNode
            }
          } else {
            return false
          }
        } else {
          currentNode = currentNode.rigth
          if (currentNode) {
            if (value === currentNode.value) {
              return currentNode
            }
          } else {
            return false
          }
        }
      }
    }
  }

Use la estructura que menciono el profe pero ahora para el metodo search, si me pudieran dar feedback estaría genial

search(value) {
        if (this.root === null) {
            return "Arbol vacio";
        } else {
            let currentNode = this.root;
            while(true) {
                if(value === currentNode.value){
                    return currentNode;
                }
                if(value < currentNode.value) {
                    if(!currentNode.left) {
                        return "No existe el valor";
                    } else {
                        currentNode = currentNode.left;
                        if(value === currentNode.value) {
                            return currentNode;
                        }
                    }
                } else {
                    if(!currentNode.right) {
                        return "No existe el valor";
                    } else {
                        currentNode = currentNode.right;
                        if(value === currentNode.value) {
                            return currentNode;
                        }
                    }
                }
            }
        }
    }

Reto cumplido con validaciones

    search(value) {
        if (value) {
            let currentNode = this.root;
            while (true) {
                if (currentNode.value === value) {
                    return console.log(currentNode);
                } else {
                    if (value < currentNode.value) {
                        if (!currentNode.left) {
                            return console.log(`${value} no existe en el Tree`);
                        } else {
                            currentNode = currentNode.left;
                        }
                    } else {
                        if (!currentNode.right) {
                            return console.log(`${value} no existe en el Tree`);
                        } else {
                            currentNode = currentNode.right;
                        }
                    }
                }
            }
        } else {
            console.log("Ingresa el valor a buscar");
        }
    }
class Node {
  constructor(value) {
    this.left = null;
    this.right = null;
    this.value = value;
  }
}

class BinarySearchTree {
  constructor() {
    this.root = null;
  }
  insert(value) {
    const newNode = new Node(value);
    if (this.root === null) {
      this.root = newNode;
    } else {
      let currentNode = this.root;
      while (true) {
        if (value < currentNode.value) {
          if (!currentNode.left) { //validamos si existe un node in the left 
            currentNode.left = newNode;// al no existir el node que estamos agregando se ubica ahi 
            return this;
          }
          currentNode = currentNode.left;//nos movemos al node left 
        } else {
          if (!currentNode.right) {
            currentNode.right = newNode;
            return this;
          }
          currentNode = currentNode.right;
        }
      }
    }
  }
  search(value) {
    let currentNode = this.root;
    while (true) {
      if (currentNode) {
        if (value === currentNode.value) {
          return currentNode;
        } else if (value > currentNode.value) {
          currentNode = currentNode.right;
        } else if (value < currentNode.value) {
          currentNode = currentNode.left;
        }
      } else {
        return 'No existe el nodo'
      }
    }
  }
}

const tree = new BinarySearchTree();
tree.insert(10);
tree.insert(4);
tree.insert(20);
tree.insert(2);
tree.insert(8);
tree.insert(17);
tree.insert(170);```

El 10 del lado de 33.

Search function

search(value) {
    if (value === this.root.value) {
      return this.root
    } else {
      let currentNode = this.root
      while (true) {
        if (value < currentNode.value) {
          currentNode = currentNode.left
        } else {
          currentNode = currentNode.right
        }
        if (currentNode) {
          if (value === currentNode.value) {
            return currentNode
          }
        } else {
          return 'Value not found'
        }
      }
    }
  }```