二叉树作为一种子节点不超过两个的树形结构,在查询检索方面的性能还是不错的。比如对于敏感词信息的检索上,无论是链表还是map,其性能都无法跟二叉树相比较。
1 定义
1.1 几个约定:
1.1.1 左节点的值<父节点的值<右节点的值
//定义节点对象
var Node=function(data,left,right){
this.data=data;
this.left=left;
this.right=right;
}
//二叉树对象
var BST=function(){
this.root=null;
this.fnInsert=fnInsert;//插入
this.fnInorder=fnInorder;//遍历
this.fnGetMin=fnGetMin;//获取最小值
this.fnGetMax=fnGetMax;//获取最大值
this.fnFind=fnFind;//检索查询
this.fnRemove=fnRemove;//删除
}
2 几个方法:
//插入节点
//插入节点
/**
* 1 从根节点开始执行插入操作
* 2 判断当前值与 当前节点的大小-依次是左节点-右节点
* 3 如果比当前节点小,且左节点不存在,放置在左节点
* 4 如果比当前节点大,且右节点不存在,放置在右节点
* @param {Object} data
*/
var fnInsert=function(data){
var node=new Node(data,null,null);
if(this.root==null){
this.root=node;
}else{
var current=this.root;
var parent;
while(true){
parent=current;
if(data>parent.data){
if(parent.right==null){
parent.right=node;
break;
}
current=parent.right;
}else{
if(parent.left==null){
parent.left=node;
break;
}
current=parent.left;
}
}
}
}
var fnInorder =function(node){
if(node!=null){
console.log(node.data);
fnInorder(node.left);
fnInorder(node.right);
}
}
//查找最小值-最左侧节点值
var fnGetMin=function(){
var current=this.root;
while(current.left!=null){
current=current.left;
}
return current.data;
}
//查找最大值-最右侧节点值
var fnGetMax=function(){
var current=this.root;
while(current.right!=null){
current=current.right;
}
return current.data;
}
//查询检索--当前节点-左节点-右节点循环遍历
var fnFind=function(data){
var current=this.root;
while(current!=null){
if(current.data==data){
return current;
}else if(current.data<data) {
current=current.right;
}else {
current=current.left;
}
}
return null;
}
//删除节点
var fnRemove=function(data){
root=fnRemoveNode(this.root,data);
}
//删除节点
/**
* 1 当前节点没有子节点-直接删除
* 2 当前节点只有一个子节点-当前节点的父节点指向其子节点
* 3 当前节点有两个子节点
* 3.1 查询当前节点右节点的最小值-或者当前节点左节点的最大值--至于为什么-看图体会
* 3.2 将上一步查找到的节点放置于当前节点
* 3.3 移除3.1查找到的节点
* @param {Object} data
*/
var fnGetSmallest=function(node){
var current=node;
while(current.left!=null){
current=current.left;
}
return current;
}
//
var fnRemoveNode=function(node,data){
if(node==null){
return null;
}
if(node.data==data){
if(node.right==null&&node.left==null){
return null;
}
if(node.left==null){
return node.right;
}
if(node.right==null){
return node.left;
}
var temNode=fnGetSmallest(node.right);
node.data=temNode.data;
node.right=fnRemoveNode(node.right,temNode.data);
return node;
}else if(data<node.data){
node.left=fnRemoveNode(node.left,data);
return node;
}else{
node.right=fnRemoveNode(node.right,data);
return node;
}
}
测试:
var bst=new BST();
bst.fnInsert(23);
bst.fnInsert(46);
bst.fnInsert(15);
bst.fnInsert(37);
bst.fnInsert(3);
bst.fnInsert(99);
bst.fnInsert(21);
bst.fnInsert(22);
bst.fnInsert(17);
bst.fnInorder(bst.root);
console.log(bst);
var min=bst.fnGetMin();//获取最小值
var max=bst.fnGetMax();//获取最大值
console.log('min,max',min,max);
var cur3=bst.fnFind(3);
var cur13=bst.fnFind(13);
console.log(cur3);
console.log(cur13);
bst.fnRemove(15);//移除节点
bst.fnInorder(bst.root);
console.log(bst);
删除前节点:
3 一个应用--统计文本单词的数量;
3.1 修改Node,添加count属性
//定义节点对象
var Node=function(data,left,right){
this.data=data;
this.count=1;
this.left=left;
this.right=right;
}
3.2 添加统计方法;
var fnUpdate=function(data){
var node=this.fnFind(data);
node.count++;
return node;
}
3.3 修改Bst
//二叉树对象
var BST=function(){
this.root=null;
this.fnInsert=fnInsert;//插入
this.fnInorder=fnInorder;//遍历
this.fnGetMin=fnGetMin;//获取最小值
this.fnGetMax=fnGetMax;//获取最大值
this.fnFind=fnFind;//检索查询
this.fnRemove=fnRemove;//删除
this.fnUpdate=fnUpdate;//更新
}
3.4测试
var str='aa,bb,dd,cc,dd,ee,aa,bb,cc,dd,dd,aa,dd,dd,aa,ee,dd,ee';
var bst=new BST();
var strArr=str.split(',');
for(var i=0;i<strArr.length;i++){
var node=bst.fnFind(strArr[i]);
if(node==null){
bst.fnInsert(strArr[i]);
}else{
bst.fnUpdate(strArr[i]);
}
}
bst.fnInorder(bst.root);
结果: