二叉查找树
二叉树
二叉树每个节点的子节点不允许超过两个。
二叉查找树
二叉查找树是一种特殊的二叉树,相对较小的值保存在左节点中,较大的值保存在右节点中。
一、二叉查找树的构造
function Node(data, left, right) {
this.data = data;
this.left = left;
this.right = right;
this.show = show;
}
function show() {
return this.data;
}
function BST() {
this.root = null;
this.insert = insert;
this.inOrder = inOrder;
this.preOrder = preOrder;
this.postOrder = postOrder;
}
二叉查找树插入一个节点的步骤:
- 设根节点为当前节点;
- 如果待插入的节点保存的数据小于当前节点,则设新的当前节点为原节点的左节点,反之,执行第四步;
- 如果当前节点的左节点为null,就将新的节点插入这个位置,退出循环;反之,继续执行下一次循环;
- 设新的当前节点为原节点的右节点
- 如果当前节点的右节点为null,就将新的节点插入这个位置,退出循环;反之,继续执行下一次循环;
function insert(data) {
var n = new Node(data, null, null);
if (this.root == null) {
this.root = n;
} else {
var current = this.root;
var parent;
while (true) {
parent = current;
if (data < current.data) {
current = current.left;
if (current== null) {
parent.left = n;
break;
}
} else {
current = current.right;
if (current == null) {
parent.right = n;
break;
}
}
}
}
二、二叉查找树的遍历
1. 先序遍历
- 先访问根节点,然后以同样的方式访问左子树和右子树。
function inOrder(node) {
if (!(node == null)) {
inOrder(node.left);
console.log(node.show()+' ');
inOrder(node.right);
}
}
2. 中序遍历
- 先访问左子树,然后访问根节点,最后访问右子树。
function preOrder(node) {
if (!(node == null)) {
console.log(node.show() + " ");
preOrder(node.left);
preOrder(node.right);
}
}
3. 后序遍历
- 先访问左子树,然后访问右子树,最后访问根节点。
function postOrder(node) {
if (!(node == null)) {
postOrder(node.left);
postOrder(node.right);
console.log(node.show() + " ");
}
}
测试代码如下:
var nums = new BST();
nums.insert(23);
nums.insert(45);
nums.insert(16);
nums.insert(37);
nums.insert(3);
nums.insert(99);
nums.insert(22);
console.log("Inorder traversal: ");
inOrder(nums.root);
console.log("Preorder traversal: ");
preOrder(nums.root);
console.log("Postorder traversal: ");
postOrder(nums.root);
测试结果:
三、二叉查找树—查找节点
1. 查找最大值和最小值
//在BST上查找最小值,只需要遍历左子树,直至找到最后一个节点
function getMin(){
var current=this.root;
while(!(current.left==null)){
current=current.left;
}
return current.data;
}
//在BST上查找最大值,只需要遍历右子树,直至找到最后一个节点
function getMax(){
var current=this.root;
while(!(current.right==null)){
current=current.right;
}
return current.data;
}
2.查找给定值
function find(data){
var current=this.root;
while(current!=null){
if(current.data==data){
return current;
}
//如果查找的值小于根节点,则向左遍历
else if(data<current.data){
current=current.left;
}
//如果查找的值大于根节点,则向右遍历
else{
current=current.right;
}
}
return null;
}
四、二叉查找树—删除节点
此部分转载自https://blog.csdn.net/isea533/article/details/80345507.
初始状态如下图所示,我们可以按照 50, 30, 80, 20, 35, 34, 32, 40, 70, 75, 100 的顺序插入到树中,就会产生下图所示的树。
1. 没有左右子节点时
在我们图中,符合这个条件的有 20,32,40,75,100,随便找个 20 来演示删除该节点:
这种情况是最简单的,我们只需要删除该节点和父节点的关系即可。删除的时候需要先判断自己和父节点的关系是左侧还是右侧,如下:
//这里忽略了父节点不存在的情况,最后会巧妙的处理这种情况
if(node.parent.left == node){
node.parent.left = null;
} else {
node.parent.right = null;
}
2. 存在左节点或者右节点时
满足这个情况的节点有 34, 70 两个节点,这里以 70 为例,如下图所示:
//先找到子节点,不需要管他是左是右
var child = null;
if(node.left != null){
child = node.left;
} else {
child = node.right;
}
//这里忽略了父节点不存在的情况,最后会巧妙的处理这种情况
//将父节点和子节点建立关系
if(node.parent.left == node){
node.parent.left = child;
} else {
node.parent.right = child;
}
child.parent = node.parent;
3. 同时存在左右子节点
满足同时存在左右节点的节点有 50,30,80,35 这 4 个节点,30 看起来更复杂,我们以 30 为例,,主要有两种方式:要么查找待删除节点左子树上的最大值,要么查找其右子树的最小值,这里以后者为例。
//获取待删除节点节点右子树的最小值,此部分的代码较简单,因此不做详细说明
var tempNode=getSmallest(node.right);
//转移值
node.data=tempNode.data;
//后续变成删除tempNode,就变成了前两种情况
//在图示例子中,就是第一种没有子节点的情况