/*
如果我们要查找的集合本身没有顺序,在频繁查找的同时还经常插入和删除,构建一棵二叉树比较合适。
*/
// 定义节点
function Node(data,left,right,parent){
this.data=data; // 结点存放的值
this.parent=parent; // 父结点
this.left=left; // 左子结点
this.right=right; // 右子结点
}
// 定义二叉排序树(BST)类
function BST() {
this.root=null; // 根结点
this.insert=insert; // 插入
this.insert2AVL=insert2AVL; // 插入,并调整为平衡二叉树
this.remove=remove; // remove和cutoff都是删除一个结点,实现方法不同
this.cutoff=cutoff;
this.preOrderTraverse=preOrderTraverse; // 前序遍历
this.inOrderTraverse=inOrderTraverse; // 中序遍历,结果是升序的
this.postOrderTraverse=preOrderTraverse;// 后序遍历
this.getMin=getMin; // 查找最小值
this.getMax=getMax; // 查找最大值
this.find=find; // 查找指定值
}
/*
插入
*/
function insert(data) {
var node=new Node(data,null,null,null);
if(this.root===null){ // 如果是一棵空树,直接 this.root=node
this.root=node;
}else{ // 如果不是空树
var cur=this.root; // 定义一个遍历指针,指向当前node,初始值为根节点
var parent; // 定义一个指针,指向当前node的父节点
while(true){
parent=cur;
if(data===cur.data){ // 如果插入的值已经存在,则终止插入
break;
}
if(data<cur.data){ //如果插入的值小于当前节点的值,遍历指针指向其left node
cur=cur.left;
if(!cur){ // 如果left node不存在,则此处(parent.left)就是目标位置。
parent.left=node;
node.parent=parent;
break;
}
}else{
cur=cur.right;
if(!cur){
parent.right=node;
node.parent=parent;
break;
}
}
}
}
}
/*
插入,并调整为平衡二叉树
*/
function insert2AVL() {
}
/*
遍历。
*/
//中序遍历,结果以数组形式返回
function inOrderTraverse() {
var arr=[];
inOrder(this.root,arr);
return arr;
}
function inOrder(BST,arr) {
if(BST){
inOrder(BST.left,arr);
arr.push(BST.data);
inOrder(BST.right,arr);
}
}
//前遍历,结果以数组形式返回
function preOrderTraverse() {
var arr=[];
preOrder(this.root,arr);
return arr;
}
function preOrder(BST,arr) { //将BST前序输出到arr数组里
if(BST){
arr.push(BST.data);
preOrder(BST.left,arr);
preOrder(BST.right,arr);
}
}
//后序遍历,结果以数组形式返回
function postOrderTraverse() {
var arr=[];
postOrder(this.root,arr);
return arr;
}
function postOrder(BST,arr) { //将BST后序输出到arr数组里
if(BST){
postOrder(BST.left,arr);
postOrder(BST.right,arr);
arr.push(BST.data);
}
}
/*
查找(最大值、最小值、特定值)
*/
function getMin() {
var cur=this.root;
while (cur.left){
cur=cur.left;
}
return cur.data;
}
function getMax() {
var cur=this.root;
while (cur.right){
cur=cur.right;
}
return cur.data;
}
function find(item) {
var cur=this.root;
while (cur){
if(cur.data===item){return true;}
if(cur.data>item){cur=cur.left;}
else {cur=cur.right;}
}
return false;
}
/*
删除方法1:不需要知道父结点
*/
function remove(data) {
removeNode(this.root, data);
}
function removeNode(node, data) {
if (node === null) {
return null;
}
if (data === node.data) {
// 没有子节点的节点
if (node.left === null && node.right === null) {
return null;
}
// 没有左子节点的节点
if (node.left === null) {
return node.right;
}
// 没有右子节点的节点
if (node.right === null) {
return node.left;
}
// 有两个子节点的节点,用删除结点的直接后继代替
var tempNode=node.right;
while (tempNode.left){ // 找到直接后继结点,也就是右子树的最小结点
tempNode=tempNode.left;
}
node.data = tempNode.data; // 将直接后继节点的值
node.right = removeNode(node.right, tempNode.data); // node的右子树等于去除直接后继结点后的子树
return node;
} else if (data < node.data) {
node.left = removeNode(node.left, data);
return node;
} else {
node.right = removeNode(node.right, data);
return node;
}
}
/*
删除方法2:结点需要知道父结点
*/
function cutoff(data) {
cut(this.root,data);
}
function cut(BST,item) {
if(!BST){return false;}
else{
if(item===BST.data){
return cutNode(BST);
}else if(item<BST.data){
return cut(BST.left,item);
}else{
return cut(BST.right,item);
}
}
}
// 从二叉排序树中删除结点node,并重接它的左或右子树
function cutNode(node) {
var q,s;
if(node.left===null&&node.right===null){ // 删除节点为叶子结点,直接设置为null,浏览器在空闲时垃圾回收
if(node===node.parent.left){node.parent.left=null;}
if(node===node.parent.right){node.parent.right=null;}
}else if(node.left===null){ // 删除结点只有右子树
/*q=node;
node=node.right; // 原结点并没有改变
q=null;*/
// 注意! 必能通过直接修改node来达到目的,要通过修改node里面的内容。
q=node.right; // 先把node的右子树保存下来
node.data=q.data;
node.left=q.left;
node.right=q.right;
q=null;
}else if(node.right===null){ // 删除结点只有左子树
q=node.left; // 先把node的左子树保存下来
node.data=q.data;
node.left=q.left;
node.right=q.right;
q=null;
}else{ // 删除结点左右子树都有
q=node; s=node.left;
while(s.right){ // 转左,再向右找到尽头(待删结点的前驱s)
q=s; s=s.right;
}
node.data=s.data; // 将直接前驱的值赋给待删结点
if(q!==node){
q.right=s.left; // 重接q的右子树
}else{
q.left=s.left; // 重接q的左子树
}
s=null;
}
return true;
}
var arr=[62,88,58,47,35,73,51,99,37,93];
var bst=new BST();
arr.forEach(function (item) {
bst.insert(item);
});
console.log(bst.preOrderTraverse()); //[ 62, 58, 47, 35, 37, 51, 88, 73, 99, 93 ]
console.log(bst.inOrderTraverse()); //[ 35, 37, 47, 51, 58, 62, 73, 88, 93, 99 ]
console.log(bst.postOrderTraverse()); //[ 62, 58, 47, 35, 37, 51, 88, 73, 99, 93 ]
console.log(bst.getMin()); //35
console.log(bst.getMax()); //99
console.log(bst.find(62)); //true
bst.remove(62);
console.log(bst.inOrderTraverse()); //[ 35, 37, 47, 51, 58, 73, 88, 93, 99 ]
bst.cutoff(58);
console.log(bst.inOrderTraverse()); //[ 35, 37, 47, 51, 73, 88, 93, 99 ]
js二叉排序树
最新推荐文章于 2023-05-23 19:11:42 发布