树是一种分层的抽象数据结构,一个树结构包含了许多有父子关系的节点,位于顶层的叫做根节点(root),是顶级的父节点。子节点分为内部节点和外部节点。至少有一个子节点的是内部节点,没有子节点的是外部节点。形象来说树的第一层至倒数第一层都是内部节点,最后一层则是外部节点。
二叉搜索树是一种只允许左侧存放比父节点小的数,右侧存放比父节点大的数。如:
创建BinarySearchTree类:
function BinarySearchTree() {
var node = function (key) {
this.key = key;
this.left = null;
this.right = null;
}
var root = null;
}插入一个键----insert方法:
this.insert = function (key) {
var newNode = new node(key);
if (root === null) {
root = newNode;
} else {
insertNode(root, newNode);
}
}
var insertNode = function (node, newNode) {
if (newNode.key < node.key) {
if (node.left === null) {
node.left = newNode;
} else {
insertNode(node.left, newNode)
}
} else {
if (newNode.key > node.key) {
if(node.right === null) {
node.right = newNode;
} else {
insertNode(node.right, newNode)
}
}
}
}
遍历:
遍历二叉树的方法有三种
1.先序遍历------preOrderTraverse:
this.preOrderTraverse = function (callback) {
preOrderTraverseNode(root , callback)
}
var preOrderTraverseNode = function (node , callback) {
if(node !== null) {
callback(node.key);
preOrderTraverseNode(node.left , callback);
preOrderTraverseNode(node.right , callback);
}
}先序遍历先访问父节点,在访问左节点,最后访问右节点
2.中序遍历-----inOrderTraverse:
this.inOrderTraverse = function (callback) {
inOrderTraverseNode(root, callback);//这里是访问者模式
}
var inOrderTraverseNode = function (node, callback) {
if (node !== null) {
inOrderTraverseNode(node.left, callback);
callback(node.key);
inOrderTraverseNode(node.right, callback);
}
}
中序遍历先访问左侧子节点,然后是父节点,最后是右侧子节点
3.后序遍历-----postOrderTraverse:
this.postOrderTraverse = function (callback) {
postOrderTraverseNode(root , callback);
}
var postOrderTraverseNode = function (node , callback) {
if (node !== null) {
postOrderTraverseNode(node.left , callback);
postOrderTraverseNode(node.right , callback);
callback(node.key);
}
}后序遍历先访问左侧子节点,然后是右侧子节点,最后是父节点
搜索最小值-----min:
this.min = function () {
return minNode(root);
}
var minNode = function (node) {
if (node) {
while (node && node.left !== null) {
node = node.left;
}
return node.key;
}
return null;
}由于二叉搜索树的结构,最小值一定在树的最后一层的最左端。
搜索最大值-----max:
this.max = function () {
return maxNode(root);
}
var maxNode = function (node) {
if (node) {
while (node && node.right !== null) {
node = node.right; }
return node.key;
}
return null;
}由于二叉搜索树的结构,最大值一定在树的最后一层的最右端
搜索一个特定的值-----search:
this.search = function (key) {
return searchNode(root , key)
}
var searchNode = function (node , key) {
if (node == null) {
return false;
} else if (node.key < key) {
return searchNode(node.right , key);
} else if (node.key > key) {
return searchNode(node.left , key);
} else {
return true;
}
}移除一个节点----- remove:
this.remove = function (key) {
root = removeNode(root , key);
}
var removeNode = function (node , key) {
if (node == null) {
return null;
}
if (node.key > key) {
removeNode(node.left , key);
} else if (node.key < key) {
removeNode(node.key , key);
} else {
//没有子节点
if (node.left == null && node.right == null) {
node = null;
return node; //返回节点以改变指针指向
} else if (node.left !== null ) {//一个左子节点
node = node.left;
return node; //返回节点以改变指针指向
} else if (node.right !== null) {//一个右子节点
node = node.right;
return node; //返回节点以改变指针指向
} else {//两个子节点
var replaceNode = findMinNode(node.right);//找到右子节点中最小的节点
node.key = replaceNode.key;
node.right = removeNode(node.right , replaceNode);
return node; //返回节点以改变指针指向
}
}
}
//选取右子节点中最小的节点
var findMinNode = function (node) {
while (node && node.left !== null) {
node = node.left;
}
return node;
} 移除一个节点时除了要把你所移除的节点变为null,还要改变指针的指向,如果没有子节点,则指针指向null,如果只有一侧的分支(只有左节点或者只有右节点),那么指针就要指向下一个子节点,如果两侧都有分支(左右节点都有)那么就要先找到当前节点的右侧分支中最小的节点,就是右侧分支最后一层的最左端的节点,将这个最小的节点代替我们当前要删除的节点,这样能保证二叉搜索树的左侧小右侧大的基本规则,最后将指针指向这个代替的节点。