二叉树和二叉查找树
**二叉树 : **二叉树是一种特殊的树,它的子节点个数不超过两个。二叉树具有一些特殊的计算性质,
使得在它们之上的一些操作异常高效。
特点:两个子节点,左子节点和右子节点,根节点用来存储数据
二叉查找树:是一种特殊的二叉树,相对小的值保存在左节点中,相对大的值保存在右节点中。这一特点使得查找的效率很高。
二叉查找树的实现
二叉查找树由节点组成,所以我们要定义的第一个对象就是Node
//左节点和右节点
//数据的实例化
var Node = function(data,left,right){
this.data = data;
this.left = null;
this.right = null;
}
//实现展示的方法
Node.prototype = function(){
show:function(){
return this.data;
}
}
Node对象即保存数据,也保存和其它节点的链接(左节点和右节点),show方法用来展示保存在节点的数据。
BST(实现查找二叉树的类):只包含一个成员,一个表示二叉树根节点的Node对象。该类的构造函数将根节点初始化为null,以此创建一个空节点。
**insert()函数:**用来向树中添加新的节点。
1、创建一个Node对象,将数据传入该对象保存
2、检查BST是否有根节点,没有,这个树是新树,该节点作为根节点,否则,进入下一步
3、如果待插入的节点不是跟根节点,那就需要准备遍历BTS,找到合适的插入位置,该过程类似插入链表。用一个变量储存当前节点,一层层的遍历BST。
4、进入BST之后,下一步就要决定将节点放在哪个地方。找到正确的插入点时,会跳出循环,
查找正确插入点的算法:
(1)设跟节点为当前节点
(2)如果待插入节点保存的数据小于当前节点,则设置新的当前节点为原节点的左节点;反之,执行第四步
(3)如果当前左节点的值为null,就将新的节点插入这个位置,退出循环,反之,继续执行下个循环。
(4)设新的当前节点为原节点的右节点。
(5)如果当前节点的右节点为null,就将新的节点插入这个位置,退出循环;反之,继续执行下个循环。
var BST = function(){
this.root = null;
}
var BST.protopyte = {
insert:function(data){
var n= new Node(date,null,null);
if(this.root == null){
this.root = n;
}else{
var current = this.root;
var parent;
while(true){
parent = current;
if(data < parent.data){
current = parent.left;
if(current == null){
parent.left = n;
break;
}
}else{
current = parent.right;
if(current == right){
parent.right = n;
break;
}
}
}
}
}
}
二叉树有三种遍历方式:中序、先序和后序。中序遍历按照节点上的键值,以升序遍历BST上的所有节点。先序遍历先访问根节点,然后访问左节点和右节点。
BST.prototype.inorder = function(node){
f(node!=null){
this.inorder(node.left);
node.show();
this.inorder(node.right);
}
}
在二叉树上进行查找
查找 BST 上的最小值和最大值非常简单。因为较小的值总是在左子节点上,在 BST 上查
找最小值,只需要遍历左子树,直到找到最后一个节点。
BST.prototype.getMin = function(){
var currentNode = this.root;
while(currentNode.left!=null){
currentNode = currentNode.left;
}
return currentNode;
}
BST.protoType.getMax = function(){
var currentNode = this.root;
while(currentNode.right!=null){
currentNode = currentNode.right;
}
return curretnNode;
}
在 BST 上查找给定值,需要比较该值和当前节点上的值的大小。通过比较,就能确定如果
给定值不在当前节点时,该向左遍历还是向右遍历。
BST.prototype.find = function(data){
var curretn = this.root;
//当前节点是否有数据
while(current!=null){
if(current.data == data){
return current;
}else if(current.data>data){
current = current.left;
}else{
current = current.right;
}
}
return null;
}
删除节点
从 BST 上删除节点的操作最复杂,其复杂程度取决于删除哪个节点。如果删除没有子节点
的节点,那么非常简单。如果节点只有一个子节点,不管是左子节点还是右子节点,就变
得稍微有点复杂了。删除包含两个子节点的节点最复杂。
为了管理删除操作的复杂度,我们使用递归操作,同时定义两个方法: remove() 和
removeNode()
从 BST 中删除节点的第一步是判断当前节点是否包含待删除的数据,如果包含,则删除该
节点;如果不包含,则比较当前节点上的数据和待删除的数据。如果待删除数据小于当前
节点上的数据,则移至当前节点的左子节点继续比较;如果删除数据大于当前节点上的数
据,则移至当前节点的右子节点继续比较。
如果待删除节点是叶子节点(没有子节点的节点),那么只需要将从父节点指向它的链接
指向 null
如果待删除节点只包含一个子节点,那么原本指向它的节点需要做些调整,使其指向它的
子节点。
最后,如果待删除节点包含两个子节点,正确的做法有两种:要么查找待删除节点左子树
上的最大值,要么查找其右子树上的最小值。这里我们选择后一种方式。
BST.prototype.getSmallest = function(node){
if(node.left == null){
return node
}
this.getSamllest(node.left)
}
BST.prototype.remove = function(data){
root = this.removeNode(this.root,data);
}
BST.prototype.removeNode = function(node,data){
if(node ==null){
return null;
}
if(data = node.data){
if(node.left ==null && data.right == null){
return null;
}
if(node.left ==null){
return node.right;
}
if(node.right == null){
return node.left;
}
var tempNode = this.getSmallest(node.right);
node.data = tempNode.data;
node.right = this.removeNode(node.right,tempNode.data);
return node;
}else if(data<node.data){
node.left = this.removeNode(node.left,data)
return node
}else{
node.right = removeNode(node.right, data);
return node;
}
}