//##树
//1.二叉树:几乎所有的树都可以表示成二叉树的形式
//2.完全二叉树:只有叶节点不是满的,且优先为左侧节点
//3.二叉搜索树(BST):
//非空左子树的所有键值小于根节点的键值
//非空右子树的所有键值大于根节点的键值
//左右子树本身也是二叉搜索树
//利用了二分查找的思想,查找所需的最大次数为BST的深度
function BinarySearchTree() {
function Node(key) {
this.key = key;
this.left = null;
this.right = null;
}
this.root = null;
BinarySearchTree.prototype.insert = function(key) {
var newNode = new Node(key);
if(this.root == null) {
this.root = newNode;
}else{
this.insertNode(this.root, newNode);
}
}
BinarySearchTree.prototype.insertNode = function(node, newNode) {
if(newNode.key < node.key) {
if(node.left == null) {
node.left = newNode;
}else{
this.insertNode(node.left, newNode);
}
}else{
if(node.right == null) {
node.right = newNode;
}else{
this.insertNode(node.right, newNode);
}
}
}
//先序遍历:先访问根节点,然后左右子树
BinarySearchTree.prototype.preOrderTraversal = function(handler) {
this.preOrderTraversalNode(this.root, handler);
}
BinarySearchTree.prototype.preOrderTraversalNode = function(node, handler) {
if(node != null) {
handler(node.key);
this.preOrderTraversalNode(node.left, handler);
this.preOrderTraversalNode(node.right, handler);
}
}
//使用
var bst = new BinarySearchTree();
var resultString = "";
bst.preOrderTraversal(function(key){
resultString += key + "";
})
alert(resultString);
//中序遍历:根节点第二次访问
BinarySearchTree.prototype.inOrderTraversal = function(handler) {
this.inOrderTraversalNode(this.root, handler);
}
BinarySearchTree.prototype.inOrderTraversalNode = function(node, handler) {
if(node != null) {
this.inOrderTraversalNode(node.left, handler);
handler(node.key);
this.inOrderTraversalNode(node.right, handler);
}
}
//后序遍历:先访问左右子树,最后访问根节点
BinarySearchTree.prototype.postOrderTraversal = function(handler) {
this.postOrderTraversalNode(this.root, handler);
}
BinarySearchTree.prototype.postOrderTraversalNode = function(node, handler) {
if(node != null) {
this.postOrderTraversalNode(node.left, handler);
this.postOrderTraversalNode(node.right, handler);
handler(node.key);
}
}
BinarySearchTree.prototype.min = function() {
var node = this.root;
while(node.left != null) {
node = node.left;
}
return node.key;
}
BinarySearchTree.prototype.max = function() {
var node = this.root;
while(node.right != null) {
node = node.right;
}
return node.key;
}
BinarySearchTree.prototype.search = function(key) {
return this.searchNode(this.root, key);
}
BinarySearchTree.prototype.searchNode = function(node,key) {
if(node == null) {
return false;
}
if(node.key > key) {
return this.searchNode(node.left, key);
}else if(node.key < key) {
return this.searchNode(node.right, key);
}else{
return true;
}
}
//删除节点:
//1.找到节点
//2.删除节点
//叶节点:父节点的left/right为null
//一个子节点:父节点指向子节点
//两个子节点:右子树的最小节点去更新这个节点,将原点删除,最后返回新的引用(前驱/后继)
BinarySearchTree.prototype.remove = function(key) {
var current = this.root;
var parent = null;
var isLeftChild = true;
while(current.key != key) {
parent = current;
if(key < current.key) {
isLeftChild = true;
current = current.left;
}else{
isLeftChild = false;
current = current.right;
}
if(current == null) {
return false;
}
}
// 3.删除的结点是叶结点
if (current.left === null && current.right === null) {
if (current == this.root) {
this.root == null
} else if (isLeftChild) {
parent.left = null
} else {
parent.right = null
}
}
// 4.删除有一个子节点的节点
else if (current.right === null) {
if (current == this.root) {
this.root = current.left
} else if (isLeftChild) {
parent.left = current.left
} else {
parent.right = current.left
}
} else if (current.left === null) {
if (current == this.root) {
this.root = current.right
} else if (isLeftChild) {
parent.left = current.right
} else {
parent.right = current.right
}
}
// 5.删除有两个节点的节点
else {
// 1.获取后继节点
var successor = this.getSuccessor(current)
// 2.判断是否是根节点
if (current == this.root) {
this.root = successor
} else if (isLeftChild) {
parent.left = successor
} else {
parent.right = successor
}
// 3.将删除节点的左子树赋值给successor
successor.left = current.left
}
return true
}
// 找后继的方法
BinarySerachTree.prototype.getSuccessor = function (delNode) {
// 1.使用变量保存临时的节点
var successorParent = delNode
var successor = delNode
var current = delNode.right // 要从右子树开始找
// 2.寻找节点
while (current != null) {
successorParent = successor
successor = current
current = current.left
}
// 3.如果是删除图中15的情况, 还需要如下代码
if (successor != delNode.right) {
successorParent.left = successorParent.right
successor.right = delNode.right
}
return successor;
}
}