数据结构标准入门-二叉树

145 阅读4分钟

二叉树查找

二叉树就是度不超过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
    }