10 KiB
id, title, challengeType, forumTopicId, dashedName
| id | title | challengeType | forumTopicId | dashedName |
|---|---|---|---|---|
| 587d8258367417b2b2512c82 | Elimina un nodo con dos hijos en un árbol binario de búsqueda | 1 | 301639 | delete-a-node-with-two-children-in-a-binary-search-tree |
--description--
La eliminación de nodos que tienen dos hijos es el caso más difícil de implementar. Eliminar un nodo como este produce dos subárboles que ya no están conectados a la estructura de árbol original. ¿Cómo podemos reconectarlos? Un método es encontrar el valor más pequeño en el subárbol derecho del nodo objetivo y reemplazar el nodo objetivo con este valor. La selección del reemplazo de esta forma asegura que es mayor que cada nodo en el subárbol izquiero se convierte en el nuevo padre del subárbol pero también es menor que cada nodo en el subárbol derecho se convierte en el nuevo padre del subárbol. Una vez reemplazados el nodo debe ser eliminado del subárbol derecho. Incluso esta operación es complicada porque el remplazo puede ser una hoja o puede ser el padre de un subárbol derecho. Si se trata de una hoja debemos eliminar la referencia de su padre. De otra forma, debe ser el hijo derecho del objetivo. En este caso, debemos reemplazar el valor objetivo con el valor del reemplazo y hacer que la referencia objetivo sea el hijo derecho del reemplazo.
--instructions--
Finalicemos nuesto método remove manejando el tercer caso. Hemos provisto un código de nuevo para los dos primeros casos. Agrega algo de código para maneja nodos objetivos con dos hijos. ¿Algún caso de arista para tener en cuenta? ¿Qué pasa si el árbol solo tiene tres nodos? Una vez que finalicemos esto completará nuestra operación de eliminación para los árboles binarios de búsqueda. ¡Buen trabajo, este es un problema bastante difícil!
--hints--
La estructura de datos BinarySearchTree debe exisitr.
assert(
(function () {
var test = false;
if (typeof BinarySearchTree !== 'undefined') {
test = new BinarySearchTree();
}
return typeof test == 'object';
})()
);
El árbol binario de búsqueda debe tener un método llamado remove.
assert(
(function () {
var test = false;
if (typeof BinarySearchTree !== 'undefined') {
test = new BinarySearchTree();
} else {
return false;
}
return typeof test.remove == 'function';
})()
);
Tratar de eliminar un elemento que no existe debe devolver null.
assert(
(function () {
var test = false;
if (typeof BinarySearchTree !== 'undefined') {
test = new BinarySearchTree();
} else {
return false;
}
return typeof test.remove == 'function' ? test.remove(100) == null : false;
})()
);
Si el nodo raíz no tiene hijos, eliminar debe establecer la raíz a null.
assert(
(function () {
var test = false;
if (typeof BinarySearchTree !== 'undefined') {
test = new BinarySearchTree();
} else {
return false;
}
test.add(500);
test.remove(500);
return typeof test.remove == 'function' ? test.inorder() == null : false;
})()
);
El método remove debe eliminar nodos hojas del árbol.
assert(
(function () {
var test = false;
if (typeof BinarySearchTree !== 'undefined') {
test = new BinarySearchTree();
} else {
return false;
}
test.add(5);
test.add(3);
test.add(7);
test.add(6);
test.add(10);
test.add(12);
test.remove(3);
test.remove(12);
test.remove(10);
return typeof test.remove == 'function'
? test.inorder().join('') == '567'
: false;
})()
);
El método remove debe eliminar nodos con un hijo.
assert(
(function () {
var test = false;
if (typeof BinarySearchTree !== 'undefined') {
test = new BinarySearchTree();
} else {
return false;
}
if (typeof test.remove !== 'function') {
return false;
}
test.add(-1);
test.add(3);
test.add(7);
test.add(16);
test.remove(16);
test.remove(7);
test.remove(3);
return test.inorder().join('') == '-1';
})()
);
Eliminar la raíz en un árbol con dos nodos debe establecer el segundo para ser la raíz.
assert(
(function () {
var test = false;
if (typeof BinarySearchTree !== 'undefined') {
test = new BinarySearchTree();
} else {
return false;
}
if (typeof test.remove !== 'function') {
return false;
}
test.add(15);
test.add(27);
test.remove(15);
return test.inorder().join('') == '27';
})()
);
El método remove debe eliminar nodos con dos hijos manteniendo la estructura del árbol binario de búsqueda.
assert(
(function () {
var test = false;
if (typeof BinarySearchTree !== 'undefined') {
test = new BinarySearchTree();
} else {
return false;
}
if (typeof test.remove !== 'function') {
return false;
}
test.add(1);
test.add(4);
test.add(3);
test.add(7);
test.add(9);
test.add(11);
test.add(14);
test.add(15);
test.add(19);
test.add(50);
test.remove(9);
if (!test.isBinarySearchTree()) {
return false;
}
test.remove(11);
if (!test.isBinarySearchTree()) {
return false;
}
test.remove(14);
if (!test.isBinarySearchTree()) {
return false;
}
test.remove(19);
if (!test.isBinarySearchTree()) {
return false;
}
test.remove(3);
if (!test.isBinarySearchTree()) {
return false;
}
test.remove(50);
if (!test.isBinarySearchTree()) {
return false;
}
test.remove(15);
if (!test.isBinarySearchTree()) {
return false;
}
return test.inorder().join('') == '147';
})()
);
La raíz debe ser extraíble en un árbol de tres nodos.
assert(
(function () {
var test = false;
if (typeof BinarySearchTree !== 'undefined') {
test = new BinarySearchTree();
} else {
return false;
}
if (typeof test.remove !== 'function') {
return false;
}
test.add(100);
test.add(50);
test.add(300);
test.remove(100);
return test.inorder().join('') == 50300;
})()
);
--seed--
--after-user-code--
BinarySearchTree.prototype = Object.assign(
BinarySearchTree.prototype,
{
add: function(value) {
var node = this.root;
if (node == null) {
this.root = new Node(value);
return;
} else {
function searchTree(node) {
if (value < node.value) {
if (node.left == null) {
node.left = new Node(value);
return;
} else if (node.left != null) {
return searchTree(node.left);
}
} else if (value > node.value) {
if (node.right == null) {
node.right = new Node(value);
return;
} else if (node.right != null) {
return searchTree(node.right);
}
} else {
return null;
}
}
return searchTree(node);
}
},
inorder: function() {
if (this.root == null) {
return null;
} else {
var result = new Array();
function traverseInOrder(node) {
if (node.left != null) {
traverseInOrder(node.left);
}
result.push(node.value);
if (node.right != null) {
traverseInOrder(node.right);
}
}
traverseInOrder(this.root);
return result;
}
},
isBinarySearchTree() {
if (this.root == null) {
return null;
} else {
var check = true;
function checkTree(node) {
if (node.left != null) {
var left = node.left;
if (left.value > node.value) {
check = false;
} else {
checkTree(left);
}
}
if (node.right != null) {
var right = node.right;
if (right.value < node.value) {
check = false;
} else {
checkTree(right);
}
}
}
checkTree(this.root);
return check;
}
}
}
);
--seed-contents--
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
function Node(value) {
this.value = value;
this.left = null;
this.right = null;
}
function BinarySearchTree() {
this.root = null;
this.remove = function(value) {
if (this.root === null) {
return null;
}
var target;
var parent = null;
// Find the target value and its parent
(function findValue(node = this.root) {
if (value == node.value) {
target = node;
} else if (value < node.value && node.left !== null) {
parent = node;
return findValue(node.left);
} else if (value < node.value && node.left === null) {
return null;
} else if (value > node.value && node.right !== null) {
parent = node;
return findValue(node.right);
} else {
return null;
}
}.bind(this)());
if (target === null) {
return null;
}
// Count the children of the target to delete
var children =
(target.left !== null ? 1 : 0) + (target.right !== null ? 1 : 0);
// Case 1: Target has no children
if (children === 0) {
if (target == this.root) {
this.root = null;
} else {
if (parent.left == target) {
parent.left = null;
} else {
parent.right = null;
}
}
}
// Case 2: Target has one child
else if (children == 1) {
var newChild = target.left !== null ? target.left : target.right;
if (parent === null) {
target.value = newChild.value;
target.left = null;
target.right = null;
} else if (newChild.value < parent.value) {
parent.left = newChild;
} else {
parent.right = newChild;
}
target = null;
}
// Case 3: Target has two children
// Only change code below this line
};
}
--solutions--
// solution required