每当放完小长假,我都会习惯性的反思和复盘一下本身的技术,尤为是端午节。为何我会写二叉树的文章呢?其实这涉及到程序员的一个成长性的问题。对于0-3年的前端程序员来讲,可能不多有机会涉及到数据结构和算法的工做中,除非去大厂或者作架构相关的工做。可是不少工做2-3年的前端工程师,业务工做已经相对熟悉了,各类技术或多或少也都使用过,那么在这个阶段,对于每一个有追求的程序员,是否是应该突破一下本身的技术瓶颈,去研究一些更深层次的知识呢?没错,这个阶段咱们最应该了解的就是数据结构,算法,设计模式相关的知识,设计模式和算法笔者在以前的文章中已经系统的总结过了,感兴趣的能够学习了解一下。前端
接下来笔者就系统的总结一下二叉树相关的知识,而且经过实际代码一步步来带你们实现一个二叉搜索树。vue
二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构每每是二叉树形式,即便是通常的树也能简单地转换为二叉树,并且二叉树的存储结构及其算法都较为简单,所以二叉树显得特别重要。二叉树特色是每一个结点最多只能有两棵子树,且有左右之分。 node
在实现以前,咱们须要先分析一下BST(二叉搜索)树。咱们要想构建一棵实用的树,咱们须要节点和方法,以下图所示: git
function BinarySearchTree() {
let Node = function(key) {
this.key = key;
this.left = null;
this.right = null;
}
let root = null;
}
复制代码
咱们按照上图的二叉搜索树的结构组织方式,来实现二叉树的基本方法。程序员
// 插入
this.insert = function(key) {
let newNode = new Node(key);
if(root === null) {
root = newNode;
}else {
insertNode(root, newNode);
}
}
复制代码
其中insertNode方法用来判断在根节点不为空时的执行逻辑,具体代码以下:github
function insertNode(node, newNode) {
// 若是新节点值小于当前节点值,则插入左子节点
if(newNode.key < node.key) {
if(node.left === null) {
node.left = newNode;
}else{
insertNode(node.left, newNode);
}
}else {
// 若是新节点值大于当前节点值,则插入右子节点
if(node.right === null) {
node.right = newNode;
}else {
insertNode(node.right, newNode);
}
}
}
复制代码
以上代码即实现了BST的插入部分逻辑,具体使用方式以下:算法
let tree = new BinarySearchTree()
tree.insert(19)
tree.insert(10)
tree.insert(20)
复制代码
以上代码生成的二叉树结构以下: 数据库
树的遍历是指访问树的每一个节点并对它们进行某种操做的过程。具体分为中序遍历,先序遍历和后序遍历。接下来我会一一介绍给你们。后端
中序遍历是一种以从最小到最大的顺序访问全部节点的遍历方式,具体实现以下:设计模式
this.inOrderTraverse = function(cb) {
inOrderTraverseNode(root, cb)
}
function inOrderTraverseNode(node, cb) {
if(node !== null) {
inOrderTraverseNode(node.left, cb)
cb(node.key)
inOrderTraverseNode(node.right, cb)
}
}
复制代码
具体遍历过程以下图所示:
先序遍历是以优先于后代节点的顺序访问每个节点。具体实现以下:
this.preOrderTraverse = function(cb) {
preOrderTraverseNode(root, cb)
}
function preOrderTraverseNode(node, cb) {
if(node !== null) {
cb(node.key)
preOrderTraverseNode(node.left, cb)
preOrderTraverseNode(node.right, cb)
}
}
复制代码
具体遍历以下图所示:
后序遍历是先访问节点的后代节点,再访问节点自己。。具体实现以下:
this.postOrderTraverse = function(cb) {
preOrderTraverseNode(root, cb)
}
function postOrderTraverseNode(node, cb) {
if(node !== null) {
postOrderTraverseNode(node.left, cb)
postOrderTraverseNode(node.right, cb)
cb(node.key)
}
}
复制代码
具体遍历顺序以下图所示:
咱们通常的搜索会有最值搜索(也就是最大值,最小值,中值)和对特定值的搜索,接下来咱们就来实现它们。
在BST树中搜索特定的值,具体实现以下:
this.search = function(key) {
return searchNode(root, key)
}
function searchNode(ndoe, key) {
if(node === null) {
return false
}
if(key < node.key) {
return searchNode(node.left, key)
}else if(key > node.key) {
return searchNode(node.right, key)
}else {
return true
}
}
复制代码
实现逻辑也很简单,这里你们能够研究一下。
由二叉树的结构特征咱们能够发现,二叉树的最左端就是最小值,二叉树的最右端就是最大值,因此咱们能够经过遍从来找到最小值,代码以下:
this.min = function() {
return minNode(root)
}
function minNode(node) {
if(node) {
while(node && node.left !== null) {
node = node.left;
}
return node.key
}
return null
}
复制代码
和求最小值同样,最大值也能够用相似的方法,代码以下:
this.max = function() {
return maxNode(root)
}
function maxNode(node) {
if(node) {
while(node && node.right !== null) {
node = node.right;
}
return node.key
}
return null
}
复制代码
移除BST中的节点相对来讲比较复杂,须要考虑不少状况,具体状况以下:
了解了上述3种状况以后咱们开始实现删除节点的逻辑:
this.remove = function(key) {
root = removeNode(root, key)
}
function removeNode(node, key) {
if(node === null) {
return null
}
if(key < node.key) {
node.left = removeNode(node.left, key)
return node
}else if(key > node.key) {
node.right = removeNode(node.right, key)
return node
}else {
// 一个叶节点
if(node.left === null && node.right === null) {
node = null;
return node
}
// 只有一个子节点的节点
if(node.left === null) {
node = node.right;
return node
}else if(node.right === null) {
node = node.left;
return node
}
// 有两个子节点的节点状况
let aux = findMinNode(node.right);
node.key = aux.key;
node.right = removeNode(node.right, aux.key);
return node
}
}
function findMinNode(node) {
if(node) {
while(node && node.left !== null) {
node = node.left;
}
return node
}
return null
}
复制代码
至此,一棵完整的搜索二叉树就实现了,是否是颇有成就感呢?本文的源码以上传至笔者的github,感兴趣的朋友能够感觉一下。
二叉树通常能够用来:
其实树的类型还有不少种,这些不一样类型的树在计算机中有很普遍的用途,好比红黑树,B树,自平衡二叉查找树,空间划分树,散列树,希尔伯特R树等,若是对这些树敢兴趣的朋友能够深刻研究一下,毕竟对本身将来的技术视野仍是颇有帮助的。
若是想学习更多前端技能,实战和学习路线, 欢迎在公众号《趣谈前端》加入咱们的技术群一块儿学习讨论,共同探索前端的边界。
二叉树 - baike.baidu.com/item/二叉树