二叉搜索树的定义
二叉搜索树是一种节点值之间具有一定数量级次序的二叉树,二叉搜索树(Binary Search Tree),又名二叉排序树(Binary Sort Tree)
二叉搜索树是具有有以下性质的二叉树:
- 若左子树不为空,则左子树上所有节点的值均小于或等于它的根节点的值
- 若右子树不为空,则右子树上所有节点的值均大于或等于它的根节点的值
- 左、右子树也分别为二叉搜索树
二叉搜索树的相关操作
function BinarySearchTree(){
function Node(key){
this.key = key;
this.left = null;
this.right = null;
}
// 初始化根节点
this.root = null;
// 插入方法 对外暴露出来的添加函数
BinarySearchTree.prototype.insert = function(key) {
// 先创建一个
let 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);
}
}
}
/*树的遍历*/
// 1.先序遍历 先处理节点本身,然后再处理它的左子树,最后处理右子树,所以称之为先序遍历
BinarySearchTree.prototype.preOrderTraversal = function(handler) {
this.preOrderTraversalNode(this.root, handler);
}
BinarySearchTree.prototype.midOrderTraversalNode = function(node, handler){
if (node != null) {
// 1.处理经过的节点
handler(node.key);
// 2.处理左边节点 左子树处理完成后,递归的压栈结束,然后从栈中移除,接着向下执行,遍历它的右子树,如果右子树遍历完后,然后向上回溯,这样就是递归的原理和执行过程
this.preOrderTraversalNode(node.left, handler);
// 3.处理右边节点
this.preOrderTraversalNode(node.right, handler);
}
}
/*
2.中序遍历
1>中序遍历其左子树
2>访问根节点
3>中序遍历其右子树
*/
BinarySearchTree.prototype.midOrderTraversal = function(handler){
this.midOrderTraversalNode(this.root, handler);
}
BinarySearchTree.prototype.midOrderTraversalNode = function(node, handler){
if (node != null) {
// 1.遍历左子树
this.midOrderTraversalNode(node.left, handler);
// 2.处理根节点
handler(node.key);
// 3.遍历右子树
this.midOrderTraversalNode(node.right, handler);
}
}
/*
3.后序遍历
1>后序遍历其左子树
2>后序遍历其右子树
3>访问根节点
*/
BinarySearchTree.prototype.postOrderTraversal = function(handler){
this.postOrderTraversalNode(this.root, handler);
}
BinarySearchTree.prototype.postOrderTraversalNode = function(node, handler){
if (node != null) {
// 1.遍历左子树
this.postOrderTraversalNode(node.left, handler);
// 2.遍历右子树
this.postOrderTraversalNode(node.right, handler);
// 3.处理根节点
handler(node.key);
}
}
// 查找树中的最大值
BinarySearchTree.prototype.max = function(){
let currentNode = this.root;
while(currentNode.right){
currentNode = currentNode.right;
}
return currentNode.key
}
// 查找树中的最小值
BinarySearchTree.prototype.min = function(){
let currentNode = this.root;
while(currentNode.left){
currentNode = current.left;
}
return currentNode.key;
}
// 搜索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){ // 从节点的左子树遍历查找
this.searchNode(node.left, key);
}else if(node.key > key){ // 从节点的右子树遍历查找
this.searchNode(node.right, key);
}else{
return true;
}
}
// 删除节点
BinarySearchTree.prototype.remove = function(key){
// 1.寻找要删除的节点
// 1.1保存一些变量
let current = this.root;
let parent = null;
let isLeftChild = true;
// 1.2遍历查找
while(node.key != key){
parent = current;
if(key < current.key) { //从左边找
current = current.left;
isLeftChild = true;
}else{
current = current.right;
isLeftChild = false;
}
// 最后还是没有找到
if(current == null) return false;
}
// 2.找到要删除的元素
// 2.1删除的节点是叶子节点
if (current.left == null && current.right == null) {
if(current == this.root){ //仅有一个节点,同时它是根节点
this.root = null
}else{
if(isLeftChild){
parent.left = null;
}else{
parent.right = null;
}
}
}else if(current.right == null){ // 2.2删除的节点有一个节点
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;
}
} else{
// 2.3删除的节点有两个节点
// 待删除节点既有左子树也有右子树:找到该节点右子树中最小值节点,使用该节点代替待删除节点,然后在右子树中删除最小值节点。
let rightNode = current.right;
let tempParent = current; // 记录最小节点的父节点,方便删除
while (rightNode.left) {
tempParent = rightNode;
rightNode = rightNode.left;
}
// 2.3.1 使用该节点代替待删除节点
if(current == this.root){
this.root = rightNode;
}else{
if(isLeftChild){
parent.left = rightNode;
}else{
parent.right = rightNode;
}
}
// 把删除节点的左右节点分别赋值给新节点
if (rightNode != current.right) {
rightNode.right = current.right;
}
if(rightNode != current.left){
rightNode.left = current.left;
}
// 2.3.2 右子树中删除最小值节点
if(current != this.root){
tempParent.left = null;
}
}
}
// 反转二叉树的操作
BinarySearchTree.prototype.invertTree = function(){
this.invertTreeNode(this.root);
}
// 递归调用
BinarySearchTree.prototype.invertTreeNode = function(root) {
// 逢空返回null
if(!root) return null;
// 节省时间不用再去反转最后的子节点
if(root.left || root.right){
let temp = root.left;
root.left = root.right;
root.right = temp;
// 递归遍历左右子树
this.invertTreeNode(root.left)
this.invertTreeNode(root.right)
}
return root;
}
}