小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
二叉搜索树
二叉搜索对树结构,在此树中,每个节点的数值比左子树上的每个结点值都大,比所有右子树上的结点都小。
在上图左侧图中,顶部浅黄色表示结点 12 大于位于其左子树中所有结点,小于位于其右子树中多有结点,而且我们将其一个子树如上图右侧提取出来其结点布局也符合上面的规则。
搜索结点
如上图,我们要搜索目标 7 首先从根结点开始进行搜索,7 小于根结点,所以在根结点左侧进行查找,跟根结点的左结点 3 进行比较,大于 3 所以在 3 的右子树中进行搜索,3 结点右结点 6 小于 7 就在6 的右子树中进行搜索。
插入结点
例如我们要将 7 插入到上面二叉树,思路根搜索差不多,通过一系列动作来到结点 6 ,7 大于 6 所以首先看一看 6 的右结点是否存在,如果存在将其放置到 6 的右结点,如果已经存在就继续通过上面搜索方式进行搜索一个适当空位置来放置 7。
删除结点
- 第一种情况,如果要删除的结点是叶结点,就可以直接删除该结点
- 第二种情况,如果要删除结点只有一个右子结点或者左子结点,移除该结点后其子结点就移动删除结点的位置
- 第三种情况,第三种情况比较复杂,删除该结点,会用左子树中最大结点或者右子树中最小结点替换该结点。
遍历
上一次已经介绍过遍历,前序、中序和后序遍历方式。
class Node{
constructor(data){
this.data = data;
// 左右子结点
this.left = null;
this.right = null
}
}
class BinarySearchTree{
constructor(){
// 初始化 root 结点
this.root = null;
}
insert(data){
//创建一个结点
let node = new Node(data);
//如果根结点为空
if(this.root == null){
this.root = node;
}else{
this.insertNode(this.root,node);
}
}
insertNode(root,newNode){
// 如果要插入的值小于根节点值,位于根节点的左侧
if(newNode.data < root.data){
//如果结点的左子结点为空进行直接将其赋值给左子结点
if(root.left == null){
root.left = newNode
}else{
this.insertNode(root.left,newNode);
}
// 如果要插入的值大于根节点值,位于根节点的右侧
}else if(newNode.data > root.data){
if(root.right == null){
root.right = newNode
}else{
this.insertNode(root.right,newNode);
}
}
}
getRootNode(){
return this.root;
}
preorder(root,cb){
// console.log(cb)
if(root != null){
cb(root);
this.preorder(root.left,cb);
this.preorder(root.right,cb);
}
}
inorder(root,cb){
if(root != null){
this.inorder(root.left,cb);
cb(root);
this.inorder(root.right,cb);
}
}
postorder(root,cb){
if(root != null){
this.postorder(root.left,cb);
this.postorder(root.right,cb);
cb(root);
}
}
}
let bst = new BinarySearchTree();
bst.insert(3)
bst.insert(5)
bst.insert(1)
bst.insert(6)
let bstRootNode = bst.getRootNode()
bst.preorder(bstRootNode,function(node){
console.log(node.data)}
);