用JS实现二叉搜索树
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用JS实现二叉搜索树相关的知识,希望对你有一定的参考价值。
二叉树的节点最多只能有两个子节点,一个左侧子节点,一个右侧子节点。
二叉搜索树(BST),是二叉树的一种,但只允许在左侧节点存储比父节点小的值,在右侧节点存储比父节点大或等于父节点的值。
1.创建BST
1.1创建BST类
首先申明BST类的基本结构
function BinarySearchTree() { var Node = function(key){ this.key = key; this.left = null; this.right = null; }; var root = null; }
下面我们实现一些基本方法
1.2 向树中插入一个键
插入一个键时,有三步:第一步,创建一个表示新节点的Node类实例;第二步,判断是否有根节点,如果没有,则插入节点为根节点;第三步,如果已经有根节点,需要一个辅助方法来判断新节点的
插入位置,方法如下
var insertNode = function(node,newNode){ if (newNode.key < node.key) { if (node.left === null) { node.left = newNode; } else{ insertNode(node.left,newNode); } } else{ if (node.right === null) { node.right = newNode; } else{ insertNode(node.right,newNode); } } }
以上方法的意思是,先用新节点和根节点作对比,判断根节点左侧(新节点小于根节点)或右侧(新节点大于根节点)子节点是否有值,如果没有则插入,如果有,则继续用新节点和根节点的子节点比
大小,做递归操作,逐步得到新节点插入位置,下面是插入节点的方法
this.insert = function(key){ var newNode = new Node(key); if (root === null) { root = newNode; } else{ insertNode(node.left, newNode); } }
1.3 遍历树
遍历一棵树是指访问树的每一个节点,并对它们进行某种操作的过程。访问树的节点有三种方法,中序,先序和后序。
1.3.1 中序遍历
以最小到最大的顺序访问所有的节点
var inOrderTraverseNode = function(node,callback){ if (node !== null) { inOrderTraverseNode(node.left,callback); callback(node.key); inOrderTraverseNode(node.right,callback); } } this.inOrderTraverse = function(callback){ inOrderTraverseNode(root,callback); }
以上代码中,inOrderTraverse方法接受一个回掉函数作为参数,来定义对遍历到的每一个节点的操作,这个方法中调用了一个辅助方法inOrderTraverseNode,用来递归遍历所有值,当递归到最后一级
时,观察辅助函数内部,调用回掉函数依次是左侧子节点,父节点,右侧子节点,所以执行回调函数顺序为按照节点值从小到大。
1.3.2 先序遍历
祖先节点优先于后代节点的顺序遍历
var preOrderTraverseNode = function(node,callback){ if (node !== null) { callback(node.key); preOrderTraverseNode(node.left,callback); preOrderTraverseNode(node.right,callback); } }; this.preOrderTraverse = function(callback){ preOrderTraverseNode(root,callback); }
以上代码中,preOrderTraverse方法接受一个回掉函数作为参数,来定义对遍历到的每一个节点的操作,这个方法中调用了一个辅助方法preOrderTraverseNode,用来递归遍历所有值,当递归到最后一级
时,观察辅助函数内部,调用回掉函数依次是父节点,左侧子节点,右侧子节点,所以遍历优先祖先节点。
1.3.3 后序遍历
先访问节点的后代节点,在访问节点本身
var postOrderTraverseNode = function(node,callback){ if (node !== null) { callback(node.key); postOrderTraverseNode(node.left,callback); postOrderTraverseNode(node.right,callback); } }; this.postOrderTraverse = function(callback){ postOrderTraverseNode(root,callback); }
以上代码中,postOrderTraverse方法接受一个回掉函数作为参数,来定义对遍历到的每一个节点的操作,这个方法中调用了一个辅助方法postOrderTraverseNode,用来递归遍历所有值,当递归到最后一级
时,观察辅助函数内部,调用回掉函数依次是左侧子节点,右侧子节点,父节点,所以遍历优先子节点。
1.4 搜索树中的值
1.4.1 最大值最小值
最大值为搜索树右下角的值,最小值为搜索树左下角的值,下面来看实现
1.最大值
var maxNode = function(node){ if (node) { while(node&&node.right !== null){ node = node.right; } return node.key; } return null; }; this.max = function(){ return maxNode(root); }
2.最小值
var minNode = function(node){ if (node) { while(node&&node.left !== null){ node = node.left; } return node.key; } return null; }; this.min = function(){ return minNode(root); }
实现最大值最小值,同样的方法,从根节点开始循环,直到右下角或左下角的值,返回回来。
1.4.2 搜索任意值
var searchNode = function(node,key){ if (node === null) { return false; } if (key<node.key) { return searchNode(node.left,key) } else if (key>node.key) { return searchNode(node.right,key) } else{ return true; } }; this.search = function(key){ return searchNode(root,key); }
逻辑其实很简单,拿给定的节点从根节点开始查找,比根节点大,则继续与根节点右侧子节点比较,比根节点大,则继续与根节点左侧子节点比较,依次递归,直到给定节点与某节点相等,表示找到,
返回true,如果没找到,返回false
1.4.3 删除一个节点
var removeNode = function(node,key){ if (node === null) { return null; } if (key<node.key) { node.left = remove(node.left,key) } else if (key>node.key) { node.left = remove(node.right,key) } // 键等于node.key else{ //叶节点 if (node.left === null&&node.right === null) { node = null; return node; } // 只有一个子节点的节点 if (node.left === null) { node = node.right; return node; } else if(node.right === null) { node = node.left; return node; } // 有两个子节点的节点 var aux = findMinNode(node.right); node.key = aux.key; node.right = removeNode(node.right,aux.key); return node; } } this.remove =function(key){ root = removeNode(root,key); }
上面当删除节点有两个子节点时,需要调用辅助方法findMinNode
var minNodeSelf = function(node){ if (node) { while(node&&node.left !== null){ node = node.left; } return node; } return null; }; this.findMinNode = function(){ return minNodeSelf(node); },
下面是实现BST的完整代码
function BinarySearchTree() { var Node = function(key){ this.key = key; this.left = null; this.right = null; }; var root = null; var insertNode = function(node,newNode){ if (newNode.key < node.key) { if (node.left === null) { node.left = newNode; } else{ insertNode(node.left,newNode); } } else{ if (node.right === null) { node.right = newNode; } else{ insertNode(node.right,newNode); } } }; var inOrderTraverseNode = function(node,callback){ if (node !== null) { inOrderTraverseNode(node.left,callback); callback(node.key); inOrderTraverseNode(node.right,callback); } }; var preOrderTraverseNode = function(node,callback){ if (node !== null) { callback(node.key); preOrderTraverseNode(node.left,callback); preOrderTraverseNode(node.right,callback); } }; var postOrderTraverseNode = function(node,callback){ if (node !== null) { callback(node.key); postOrderTraverseNode(node.left,callback); postOrderTraverseNode(node.right,callback); } }; var maxNode = function(node){ if (node) { while(node&&node.right !== null){ node = node.right; } return node.key; } return null; }; var minNode = function(node){ if (node) { while(node&&node.left !== null){ node = node.left; } return node.key; } return null; }; var minNodeSelf = function(node){ if (node) { while(node&&node.left !== null){ node = node.left; } return node; } return null; }; var searchNode = function(node,key){ if (node === null) { return false; } if (key<node.key) { return searchNode(node.left,key) } else if (key>node.key) { return searchNode(node.right,key) } else{ return true; } }; var removeNode = function(node,key){ if (node === null) { return null; } if (key<node.key) { node.left = remove(node.left,key) } else if (key>node.key) { node.left = remove(node.right,key) } // 键等于node.key else{ //叶节点 if (node.left === null&&node.right === null) { node = null; return node; } // 只有一个子节点的节点 if (node.left === null) { node = node.right; return node; } else if(node.right === null) { node = node.left; return node; } // 有两个子节点的节点 var aux = findMinNode(node.right); node.key = aux.key; node.right = removeNode(node.right,aux.key); return node; } }; this.insert = function(key){ var newNode = new Node(key); if (root === null) { root = newNode; } else{ insertNode(node.left, newNode); } }, this.inOrderTraverse = function(callback){ inOrderTraverseNode(root,callback); }, this.preOrderTraverse = function(callback){ preOrderTraverseNode(root,callback); }, this.postOrderTraverse = function(callback){ postOrderTraverseNode(root,callback); }, this.max = function(){ return maxNode(root); }, this.min = function(){ return minNode(root); }, this.findMinNode = function(){ return minNodeSelf(root); }, this.search = function(key){ return searchNode(root,key); }, this.remove =function(key){ root = removeNode(root,key); } }
以上是关于用JS实现二叉搜索树的主要内容,如果未能解决你的问题,请参考以下文章