学习js数据结构与算法-树(2)

157 阅读3分钟

这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」。

个人觉得要想进大厂,就必须学习了解算法和数据结构,经历了多次面试之后,也知道了算法和数据结构的重要性,所以,我也打算从今天开始,进入学习,下载了一下电子书,边看书,边跟着书的例子来敲一下代码,下面就开始总结一下对算法和数据结构的学习吧。

第二十八天:继续学习

向二叉搜索树中插入一个键

insert(key) {
  if(this.root === null) {
    this.root = new Node(key)
  }else {
    this.insertNode(this.root, key)
  }
}

如果根节点没值的话,直接创建一个节点实例赋值给根节点,否则利用辅助方法插入节点到已经有值的树中。

下面实现它的辅助方法

insertNode(node, key) {
  if(this.compareFn(node.key, 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)
    }
  }
}

首先判断一下当前节点的值和传入的值谁大,如果当前值比传入的值小,那么就应该插入左侧,再判断左侧现在有没有值,没有的话直接插入一个新的节点,有的话,递归走当前辅助方法插入。如果当前值比传入的值大,就应该插入右侧,判断和左侧的基本一样,如果右侧没有值,直接插入一个节点,有值的话,递归辅助方法插入。

树的遍历

树的遍历有几种方案:中序遍历、先序遍历和后序遍历。

中序遍历

中序遍历是一种以上行顺序访问BST所有节点的遍历方式,从最小到最大的顺序访问所有节点。

inOrderTraverser(callback) {
  this.inOrderTraverserNode(this.root, callback) 
}

遍历方法接收一个回调,回调函数用来定义我们对遍历到的每个节点进行操作。

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

跳用这个辅助方法的时候,我们在上面传入的参数是root,从根节点开始遍历,然后如果当前的节点不为空,就递归左侧,然后执行回调函数,然后如果左侧的值遍历完了,就回到上一层遍历右侧,如果右侧的值也为null,继续回到上一层。下面的图可以清晰的看到遍历过程

image.png

遍历出来的数据是:3 5 6 7 8 9 10 11 12 13 14 15 18 20 25,可以看出它是从小到大排序的

先序遍历

先序遍历是以优先于后代节点的顺序访问每个节点的

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);
} }

和上面的中序遍历其实差不多,不一样的是,这次我们先在递归左侧前处理了这个节点的值,每当进入递归,就先打印出这个值,然后走递归,当左侧递归走完之后就会走右侧递归,然后一层层的往上走。下面的图清晰的知道路径

image.png

所以输出的值是:11、7、5、3、6、9、8、10、15、13、12、14、20、18、25

后序遍历

后序遍历是先访问节点的后代节点,在访问节点本身

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);
} }

后序遍历是先把左右遍历都走完,在对数据进行操作,可以看到上面,先访问左侧子节点,然后是右侧子节点,最后才是父几点。下图可以清晰的看到过程。

image.png