二叉查找树
定义: 一颗二叉查找树是一颗二叉树,其中每个节点都含有一个comparable的键,且每个节点的键都大于其左子树中的任一键而小于右子树的任一结点的键。
class Node {
constructor (key, value) {
this.key = key;
this.value = value;
this.left = null;
this.right = null;
this.N = 1;
}
}
class BST {
constructor (root) {
this.root = root;
}
size (node) {
if (node === undefined) {
return this.root.N;
}else if(node === null){
return 0;
}
return node.N;
}
get (node, searchKey) {
let key;
if (arguments.length === 2){
key = searchKey;
} else {
node = this.root;
key = arguments[0];
}
if(node === null || key === undefined) {
return null;
}
let cmp = compare(key, node.key);
if(cmp > 0) {
return this.get(node.left, key);
} else if (cmp === 0) {
return node.value;
} else {
return this.get(node.right, key);
}
}
put (node, key, value){
let temp;
if (arguments.length === 3){
key = key;
value = value;
} else {
node = this.root;
key = arguments[0];
value = arguments[1];
}
temp = new Node(key, value);
if (this.root === undefined){
this.root = temp;
}
if (node == null) {
return temp;
}
let cmp = compare(key, node.key);
if (cmp > 0) {
node.left = this.put(node.left, key, value);
} else if (cmp === 0) {
node.value = value;
}else {
node.right = this.put(node.right, key, value);
}
node.N = this.size(node.left) + this.size(node.right) + 1;
return node;
}
min(){}
floor(){}//见后面
rank(){}
select(){}
}
function compare(key1, key2){
if (key1 < key2) {
return 1;
}
if (key1 === key2) {
return 0;
}
if (key1 > key2) {
return -1;
}
}
在N个随机键构造的二叉查找树中,查找命中平均所需的比较次数为2lnN
二叉查找树api
关于查找不大于key的最大结点。每查到一个小于或等于key的结点会出现两种情况
1. 该结点无右子树,则最大值即为该结点
2. 该结点有右子树,则查询右子树满足条件的结点,若不存在则该结点为最大key节点,若存在最大结点就是其右子树的结点。
this.floor(node.right, key) || node ;
function min (node) {
let root;
if(arguments.length === 0){
node = this.root;
root = this.root;
} else {
root = node;
}
if (node == null) {
return null;
}
while(root.left !== null){
root =root.left;
}
return root;
}
function floor (node, key) {
if(arguments.length === 1){
node = this.root;
key = arguments[0];
}
let min = null;
if (node === null) {
return min;
}
let cmp = compare(key, node.key);
if (cmp > 0) {
return (min = this.floor(node.left, key));
} else if (cmp < 0) {
min = this.floor(node.right, key) || node ;
return min;
} else {
return node;
}
}
rank()和select() 查询key的位置
function select (node, k) {
if (arguments.length === 1) {
node = this.root;
k = arguments[0];
}
if(node == null || k > this.root.N){
return 0;
}
let index = this.size(node.left);
if (index > k){
return this.select (node.left, k);
} else if (index === k){
return node;
} else {
return this.select (node.right, k - index -1);
}
}
function rank (node, key) {
if (arguments.length === 1) {
node = this.root;
key = arguments[0];
}
if (node === null) return 0;
let cmp = compare(key, node.key);
if(cmp > 0){
return this.rank(node.left, key);
} else if(cmp < 0) {
return this.size(node.left) + 1 + this.rank(node.right, key);
} else {
return this.size(node.left);
}
}
删除操作
- 查询被删除结点t的后继结点x。
- 将t的左子树转为x的左子树,t已经删除了x的右子树作为x的右子树。
- 将x作为原来t所在的位置。
function deleteMin(node){
if ( arguments.length === 0 ){
return this.root = this.deleteMin(this.root);
}
if(node == null){
return null;
}
if ( node.left == null ){
return node.right;
}
node.left = this.deleteMin(node.left);
node.N = this.size(node.left) + this.size(node.right) + 1;
return node;
}
function delete (node, key) {
if(arguments.length === 1){
key = arguments[0];
return this.root = this.delete(this.root, key);
}
if(key == null || node == null){
return null;
}
let cmp = compare(key, node.key);
if(cmp > 0) {
node.left = this.delete (node.left, key);
}else if(cmp < 0) {
node.right = this.delete (node.right, key);
}else {
let x = this.min(node.right);console.log(x)
if(x){
x.right = this.deleteMin(node.right);
x.left = node.left;
} else {
return node.left;
}
node = x;
}
node.N = this.size(node.left) + this.size(node.right) + 1;
return node;
}
查找给定范围的key
使用中序遍历
function keys (node, queue, lo, hi) {
if (arguments.length === 2) {
let Queue = [];
this.keys(this.root, Queue, arguments[0], arguments[1]);
return Queue;
}
if(node == null){
return;
}
let cmp1 = compare(lo, node.key);
let cmp2 = compare(hi, node.key);
if(cmp1 > 0) this.keys(node.left, queue, lo, hi);
if(cmp1 >= 0 && cmp2 <= 0) queue.push(node.key);
if(cmp2 < 0) this.keys(node.right, queue, lo, hi);
}