二叉树查找
二叉树就是度不超过2的树(每个结点最多有两个子结点)
满二叉树: 一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。 完全二叉树: 叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树
二叉查找树
二叉查找树是一种特殊的二叉树,相对较小的值保存在左节点中,较大的值保存在右节点中。二叉树其实就是由一个一个的结点及其之间的关系组成的,按照面向对象的 思想,我们 设计一个结点类来描述结点这个事物。
实现思想
- 如果当前树中没有任何一个结点,则直接把新结点当做根结点使用
- 如果当前树不为空,则从根结点开始
- 如果新结点的key小于当前结点的key,则继续找当前结点的左子结点;
- 如果新结点的key大于当前结点的key,则继续找当前结点的右子结点;
- 如果新结点的key等于当前结点的key,则树中已经存在这样的结点,替换该结点的value值即 可。
查询方法get实现思想
- 如果要查询的key小于当前结点的key,则继续找当前结点的左子结点
- 如果要查询的key大于当前结点的key,则继续找当前结点的右子结点
- 如果要查询的key等于当前结点的key,则树中返回当前结点的value
删除方法delete实现思想
- 找到被删除结点
- 找到被删除结点右子树中的最小结点minNode
- 删除右子树中的最小结点
- 让被删除结点的左子树成为最小结点minNode的左子树,让被删除结点的右子树称为最小结点 minNode的右子树
- 让被删除结点的父节点指向最小结点minNode
代码实现
class BinarySearchTree {
constructor() {
this.root=null
this.size=0
}
// 从数据结构中加元素
put(key,value){
this.root=this.putInRoot(this.root,key,value)
}
// 具体方法
putInRoot(tree,key,value){
if(tree==null){
this.size++
return new Node(null,null,key,value)
}
// 键值比当前树小,走左子树
if(tree.key>key){
tree.left=this.putInRoot(tree.left,key,value)
// 键值比当前树大,走右子树
}else if(tree.key<key){
tree.right=this.putInRoot(tree.right,key,value)
//
}else{
tree.value=value
}
return tree
}
// 获得
get(key){
return this.getNodeByKey(this.root,key)
}
// 内部方法
getNodeByKey(tree,key){
if(tree==null){
return null
}
if(tree.key<key){
return this.getNodeByKey(tree.right,key)
}else if(tree.key>key){
return this.getNodeByKey(tree.left,key)
}else{
console.log("debugger:"+tree.value)
return tree.value
}
}
// 获取长度
getSize(){
return this.size
}
delete(key){
this.deleteNodeByKey(this.root,key)
}
deleteNodeByKey(tree,key){
if(tree==null){
return null
}
if(key>tree.key){
tree.right=this.delete(tree.right,key)
}else if(key<tree.key){
tree.left=this.delete(tree.left,key)
}else {
// 将minNode保存下来
let minNode=tree.right
if(minNode.left!=null){
minNode=minNode.left
}
// 删除原来的minNode
let node=tree.right
while(node.left!=null){
if(node.left.left==null){
node.left=null
}else{
node=node.left
}
}
minNode.left=tree.left
minNode.right=tree.right
tree=minNode
n--
}
}
}
class Node {
constructor(left,right,key,value) {
this.left=left
this.right=right
this.key=key
this.value=value
}
}
let bst=new BinarySearchTree()
bst.put(1,"郭明")
console.log(bst.get(1))
console.log(bst.getSize())
前序遍历
实现步骤
- 把当前结点的key放入到队列中;
- 找到当前结点的左子树,如果不为空,递归遍历左子树
- 找到当前结点的右子树,如果不为空,递归遍历右子树
代码实现
preErgodic(){
let keys=new Queue()
this.preErgodicNodeTree(this.root,keys)
return keys
}
preErgodicNodeTree(tree,keys){
if(tree==null){
return
}
keys.enqueue(tree.key)
if(tree.left!=null){
preErgodicNodeTree(tree.left,keys)
}
if(tree.right!=null){
preErgodicNodeTree(tree.right,keys)
}
}
中序遍历
实现步骤
- 找到当前结点的左子树,如果不为空,递归遍历左子树
- 把当前结点的key放入到队列中;
- 找到当前结点的右子树,如果不为空,递归遍历右子树
实现代码
midErgodic(){
let keys=new Queue()
midErgodicNodeTree(this.root,keys)
return keys
}
midErgodicNodeTree(tree,keys){
if(tree==null){
return
}
if(tree.left!=null){
midErgodicNodeTree(tree.left,keys)
}
keys.enqueue(tree.key)
if(tree.right!=null){
midErgodicNodeTree(tree.right,keys)
}
}
后序遍历
实现步骤
- 找到当前结点的左子树,如果不为空,递归遍历左子树
- 找到当前结点的右子树,如果不为空,递归遍历右子树
- 把当前结点的key放入到队列中
代码实现
afterErgodic(){
let keys=new Queue()
afterErgodicNodeTree(this.root,keys)
return keys
}
afterErgodicNodeTree(tree,keys){
if(tree==null){
return ;
}
if(tree.left!=null){
afterErgodicNodeTree(tree.left,keys)
}
if(tree.right!=null){
afterErgodicNodeTree(tree.right,keys)
}
keys.enqueue(tree.key)
}
层序遍历
所谓的层序遍历,就是从根节点(第一层)开始,依次向下,获取每一层所有结点的值.
实现步骤
- 创建队列,存储每一层的结点
- 使用循环从队列中弹出一个结点:
- 获取当前结点的key;
- 如果当前结点的左子结点不为空,则把左子结点放入到队列中
- 如果当前结点的右子结点不为空,则把右子结点放入到队列中
代码实现
layerErgodic(){
let nodes=new Array(this.size)
let keys=new Queue()
nodes.push(this.root)
while(nodes.length!=null){
let currentNode=nodes.shift()
keys.enqueue(currentNode.key)
if(currentNode.left!=null){
nodes.push(currentNode.left)
}
if(currentNode.right!=null){
nodes.push(currentNode.right)
}
}
return keys
}