二叉树

二叉树结构图:

树顶部的节点是根节点,有子元素的节点叫做内部节点,没有子元素的节点叫做外部节点节点

节点和它的子节点称为子树

节点左侧存储小值,节点右侧存储大值

使用js实现二叉树结构,待实现功能如下:

insert(key) 向树中插入新的键
search(key) 在树中查找一个键,如果节点存在,返回true,如果不存在,返回false
inOrderTraverse() 通过中序遍历方式遍历所有节点(由小到大排序)
preOrderTraverse() 通过先序遍历方式遍历所有节点()
postOrderTraverse() 通过后序遍历方式遍历所有节点
min() 返回树中最小的值/键
max() 返回树中最大的值/键
remove(key) 从树中移除某个键

 代码(二叉树数据结构会大量运用递归):

class Node{
    // 节点
    constructor(key){
        this.key = key
        this.left = null
        this.right = null
    }
}

const compare = {
    Less_Than : -1,
    Bigger_Than : 1
}

function defaultCompare(a, b){
    // 比较大小
    if(a === b){
        return 0
    }
    return a < b? compare.Less_Than : compare.Bigger_Than
}

创建二叉树类:

class BinarySearchTree{
    // 二叉树
    constructor(compareFn = defaultCompare){
        this.compareFn = compareFn  // 用来比较节点值
        this.root = null    // 根节点
    }
}

插入节点:

根据左小右大,通过递归逐级下查,查找待添加节点的位置

insert(key){
    if (this.root === null){
        this.root = new Node(key)
    } else{
        this._insertNode(this.root, key)
    }
}
_insertNode(node, key){
    if(this.compareFn(key, node.key) === compare.Less_Than){
        if(node.left === null){
            node.left = new Node(key)
        }else{
            this._insertNode(node.left, key)
        }
    }else{
        if(node.right === null){
            node.right = new Node(key)
        }else{
            this._insertNode(node.right, key)
        }
    }
}

查找键是否存在:

和插入节点类似,通过递归,沿着一个方向逐级向下查找,当查到null时,即不存在

search(key){
    return this._searchNode(this.root, key)
}
_searchNode(node, key){
    if(node === null){
        return false
    }
    if(this.compareFn(key, node.key) === compare.Less_Than){
        return this._searchNode(node.left, key)
    } else if(this.compareFn(key, node.key) === compare.Bigger_Than){
        return this._searchNode(node.right, key)
    } else{
        return true
    }
}

中序遍历所有节点的大小(由小到大排序):

callback参数传入一个回调函数,用来遍历后执行

例如传入const a = (val) => { console.log(val) }

返回结果是:由小到大依次排列的节点值,例:1,2,3,4,5,6,7,8,9

inOrderTraverse(callback){
    this._inOrderTraverseNode(this.root, callback)
}
_inOrderTraverseNode(node, callback){
    if(node != null){
        this._inOrderTraverseNode(node.left, callback)
        callback(node.key)
        this._inOrderTraverseNode(node.right, callback)
    }
}

先序遍历:

和中序遍历类似,只是遍历结果发生了改变

preOrderTraverse(callback){
    this._preOrderTraverseNode(this.root, callback)
}
_preOrderTraverseNode(node, callback){
    if(node !== null){
        callback(node.key)
        this._preOrderTraverseNode(node.left, callback)
        this._preOrderTraverseNode(node.right, callback)
    }
}

后序遍历:

和中序遍历类似,只是遍历结果发生了改变

postOrderTraverse(callback){
    this._postOrderTraverseNode(this.root, callback)
}
_postOrderTraverseNode(node, callback){
    if(node !== null){
        this._postOrderTraverseNode(node.left, callback)
        this._postOrderTraverseNode(node.right, callback)
        callback(node.key)
    }
}

最小值查询:

直接查找最左侧子树的最左侧节点

min(){
    return this._minNode(this.root)
}
_minNode(node){
    if(node !== null && node.left !== null){
        return this._minNode(node.left)
    }else{
        return node
    }
}

最大值查询:

直接查找最右侧子树的最右侧节点

max(){
    return this._maxNode(this.root)
}
_maxNode(node){
    if(node !== null && node.right !== null){
        return this._maxNode(node.right)
    }else{
        return node
    }
}

删除指定节点:

首先,找到待删除节点,若找不到,则返回原树

若找到,分为三种情况:

  1.节点为叶节点,即左右节点都为null,直接删掉即可

  

  2.节点为内部节点但左右有一侧为null,则用另一侧节点代替当前节点

  

  3.节点左右侧都有,则需要找到右侧树中的最小值来取代当前节点,然后再对右侧树执行一个末位节点删除,删除掉重复的原替代值

  

remove(key){
    this.root = this._removeNode(key, this.root)
}
_removeNode(key, node){
    if(node === null){
        return null
    }
    if(this.compareFn(key, node.key) === compare.Less_Than){
        node.left = this._removeNode(key, node.left)
        return node
    }else if(this.compareFn(key, node.key) === compare.Bigger_Than){
        node.right = this._removeNode(key, node.right)
        return node
    }else{
        // 第一种情况,删除末位节点
        if(node.left === null && node.right === null){
            node = null
            return node
        }
        // 第二种情况,左或右节点为Null
        if(node.left === null){
            node = node.right
            return node
        }else if(node.right === null){
            node = node.left
            return node
        }
        // 第三种情况,左右都有子节点
        // 找到右侧子树中最小的节点
        const newNode = this._minNode(node.right)
        node.key = newNode.key
        // 删除右侧子树中最小的节点
        this._removeNode(newNode.key, node.right)
        return node
    }
}

 

posted @ 2021-10-25 12:15  邢韬  阅读(296)  评论(0编辑  收藏  举报