// 先序遍历的顺序:根节点、左节点、右节点
// 先序遍历可以打印出树的结构
root = this.root
DLR(root) {
if(root) {
console.(root.value)
this.DLR(root.left)
this.DLR(root.right)
}
}
// 中序遍历顺序:左节点、根节点、右节点
// 二叉搜索树的中序遍历结果得到的就是有序的值
LDR(root) {
if(root) {
this.LDR(root.left)
console.log(root.value)
this.LDR(root.right)
}
}
// 后序遍历顺序:左节点、右节点、根节点
// 后序遍历可以用于从叶子节点向根节点访问
LRD(root) {
if(root) {
this.LRD(root.left)
this.LRD(root.right)
console.log(root.value)
}
}
非递归遍历比递归遍历要复杂,我们需要借助到栈这种数据结构。
栈的特点是先进后出,所以我们可以**「将后处理的节点先进栈,先处理的节点后进栈」**。
root = this.root
// 先序遍历的顺序是根左右,所以先入栈右节点,再入栈左节点
Dlr() {
if(!root) return null
let s = new Stack()
s.push(root)
while(s.getCount()) {
node = s.pop()
console.log(node.value)
if(node.right) {
s.push(node.right)
}
if(node.left) {
s.push(node.left)
}
}
}
// 中序遍历顺序是左根右,先将根节点和所有的左节点入栈
LDR() {
if(!node) return null
let s = new Stack()
s.push(root)
while(s.getCount()) {
if(root) {
s.push(root)
root = root.left
}
node = s.pop()
console.log(node.value)
// 如果出栈的节点存在右子树,将该子树的所有左节点入栈
root = node.right()
}
}
// 由于左右节点没有直接的访问方法,所以先入栈右子树,然后入栈左子树,将得到的结果数组翻转
Lrd(){
if(!root) return null
let s = new Stack()
let res = []
s.push(root)
while(s.getCount()){
node = s.pop()
res.push(node.value)
if(node.left) s.push(node.left)
if(node.right) s.push(node.right)
}
return res.reverse()
}
接下来就是层次遍历,层次遍历也需要借助到别的数据结构,这里使用队列实现。
BFS() {
if (!this.root) return null
let q = new Queue()
q.enqueue(this.root)
while (!q.isEmpty()) {
let n = q.deQueue()
console.log(n.value)
if (n.left) q.enQueue(n.left)
if (n.right) q.enQueue(n.right)
}
}
层次遍历的思路是**「将一个节点出栈的同时,将它的左节点和右节点入栈」**。队列先进先出的特点可以保证一层的节点遍历完再遍历下一层的节点。
二叉树的其他操作
「获取最大或最小值」。由于二叉搜索树的特性,小值在左子树,大值在右子树,所以我们只需要比较当前节点的值,就知道向左还是向右遍历。找最小值一直向左遍历,最大值一直向右遍历。
root = this.root
getMin() {
return this._getMin(root).value
}
_getMin(node) {
if(!node.left) return node
return this.getMin(node.left)
}
getMax() {
return this._getMax(root).value
}
_getMax(node) {
if(!node.left) return node.value
return this.getMax(node.right)
}
「第n大的值」。二叉搜索树由于只能从根节点往子节点遍历,所以我们没办法直接获取到节点的排名。所以我们需要对二叉树的定义改一下,为每一个节点添加一个size属性,直接标明该节点前有多少节点,为了方便计算,包含自身。
class Node{
constructor(value) {
this.value = value
this.left = null
this.right= null
this.size = 1
}
_getSize(node) {
return node ? node.size : 0
}
addChild(node, v) {
if (!node) return new Node(v)
// 节点下插入一个子节点时,该节点的size+1
if (node.value > v) {
node.size++
node.left = this.addChild(node.left, v)
} else if (node.value < v) {
node.size++
node.right = this.addChild(node.right, v)
}
return node
}
select(k) {
let node = this._select(this.root, k)
return node ? node.value : null
}
_select(node, k) {
if (!node) return null
// 先获取根节点的左子树的size,如果k小于size,就在左子树查找,如果k大于size就在右子树寻找
let size = node.left ? node.left.size : 0
if (size > k) return this._select(node.left, k)
// 在右子树的情况下,减去左子树和根节点,问题就变成在右子树中,第(k - size - 1)个节点
if (size < k) return this._select(node.right, k - size - 1)
return node
}
}
「删除节点」。在二叉树上删除一个节点是一个复杂的操作,首先要分多种情况考虑,其次删除节点后,还要保证二叉搜索树的特性。删除节点有三种情况:
- 没有子节点
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
数据结构与算法
这一块在笔试、面试的代码题中考核较多,其中常考的数据结构主要有:数组、链表、队列、栈、Set、Map、哈希表等,不同数据结构有不同的方法以及储存原理,这些算是技术岗的必备知识。算法部分主要分为两大块,排序算法与一些其他算法题。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
排序算法根据考频高低主要有:快速排序、归并排序、堆排序、冒泡排序、插入排序、选择排序、希尔排序、桶排序、基数排序、Timsort这十种,这类考核点要么是算法的时间、空间复杂度、稳定度,要么是直接手写代码,故在理解算法原理的同时,对JS语言版的排序算法代码也要加强记忆。
- 二叉树层序遍历
- B 树的特性,B 树和 B+树的区别
- 尾递归
- 如何写一个大数阶乘?递归的方法会出现什么问题?
- 把多维数组变成一维数组的方法
- 知道的排序算法 说一下冒泡快排的原理
- Heap 排序方法的原理?复杂度?
- 几种常见的排序算法,手写
- 数组的去重,尽可能写出多个方法
- 如果有一个大的数组,都是整型,怎么找出最大的前 10 个数
- 知道数据结构里面的常见的数据结构
- 找出数组中第 k 大的数组出现多少次,比如数组【1,2, 4,4,3,5】第二大的数字是 4,出现两次,所以返回 2
- 合并两个有序数组
- 给一个数,去一个已经排好序的数组中寻找这个数的位 置(通过快速查找,二分查找)
度,要么是直接手写代码,故在理解算法原理的同时,对JS语言版的排序算法代码也要加强记忆。
- 二叉树层序遍历
- B 树的特性,B 树和 B+树的区别
- 尾递归
- 如何写一个大数阶乘?递归的方法会出现什么问题?
- 把多维数组变成一维数组的方法
- 知道的排序算法 说一下冒泡快排的原理
- Heap 排序方法的原理?复杂度?
- 几种常见的排序算法,手写
- 数组的去重,尽可能写出多个方法
- 如果有一个大的数组,都是整型,怎么找出最大的前 10 个数
- 知道数据结构里面的常见的数据结构
- 找出数组中第 k 大的数组出现多少次,比如数组【1,2, 4,4,3,5】第二大的数字是 4,出现两次,所以返回 2
- 合并两个有序数组
- 给一个数,去一个已经排好序的数组中寻找这个数的位 置(通过快速查找,二分查找)
[外链图片转存中…(img-dU3toc1z-1710711891213)]