盒子
盒子
文章目录
  1. 二叉树
  2. 二叉搜索树
  3. 平衡二叉树
  4. 前缀树

二叉树

二叉树

二叉树是一种非常重要的数据结构。在算法题中经常会使用到,在面试中的占比也是非常大的。

先来说说树的定义。

树是由n(n>=1)个有限节点组成的一个由层级关系的集合。有以下特点:

  • 每个节点有零个或多个子节点;
  • 没有父节点的节点称为根节点;
  • 每个非根节点有且只有一个父节点;
  • 除根节点外,每个子节点可以分为多个不相交的子树。

简单来说,二叉树的就是每个节点最多有两个子节点的树

在二叉树中,又有两种特殊形态:满二叉树完全二叉树

满二叉树简单的来说就是,除最后一层无子节点外,所有节点都有两个子节点的树。

完全二叉树简单的说就是,深度为h、(1~h-1)层的节点数都达最大个数且第h层所有的节点都连续集中在树的左边的树。

二叉搜索树

二叉搜索树的定义为二叉搜索树中的每个节点的值都比它左子树上的大,比它右子树上的小

这种存储方式非常适合数据搜索,这是一种类似于折半查找的搜索方式,时间复杂度为O(logN)。

对二叉树有插入和删除节点操作。

插入节点比较简单,对比当前节点和插入节点的值,再从左或从右向下递归即可。

删除节点分为三种情况。

  • 删除的节点没有子节点,也就是叶子节点;
  • 删除的节点只有左子树或右子树;
  • 删除的节点既有左子树又有右子树。

对于第一种情况,直接删除即可。第二种情况也相对简单,删除节点后直接用子树替换该节点。

主要是第三种情况比较复杂,这时候又出现两个概念,叫前驱节点后继节点

中序遍历中,某个节点之前的节点叫做前驱节点,之后的叫做后继节点。

在删除节点时,如果该节点既有左子树又有右子树,使用该节点的最小后继节点代替该节点即可。

然后讲树的遍历。树的遍历分为深度优先和广度优先两种,其中深度优先又分为先序遍历、中序遍历、后序遍历,广度优先主要是层次遍历

常问的就是三种遍历的递归遍历和非递归遍历。先简单的说三种遍历方式的遍历顺序:

先序遍历:根、左、右;

中序遍历:左、根、右;

后续遍历:左、右、根。

二叉树的遍历

先序遍历的结果为:ABDECF。中序遍历的结果为:DBEAFC。后序遍历的结果为:DEBFCA。

层次遍历的结果为:ABCDEF。

递归遍历很简单,代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 先序遍历
preTraversal() {
this._pre(this.root)
}
_pre(node) {
if (node) {
console.log(node.value)
this._pre(node.left)
this._pre(node.right)
}
}

// 中序遍历
midTraversal() {
this._mid(this.root)
}
_mid(node) {
if (node) {
this._mid(node.left)
console.log(node.value)
this._mid(node.right)
}
}

// 后序遍历
backTraversal() {
this._back(this.root)
}
_back(node) {
if (node) {
this._back(node.left)
this._back(node.right)
console.log(node.value)
}
}

非递归遍历需要使用到这种数据结构,每出栈一个节点就对其记录。

非递归先序遍历思路如下。先序遍历先访问左子树,而栈遵循的是先进后出的原则。所以顺序应该先入栈右节点后入栈左节点。大致顺序为,将根节点入栈,访问该根节点是否有子节点,如果有两个子节点,先入栈右节点,再入栈子节点,此时左节点在栈顶。访问该节点是否有子节点,重复上述操作(网上偷个图)。

先序非递归

非递归中序遍历思路。先将根节点入栈,然后一直访问左节点并入栈,直到为空。然后每出栈一个节点后,都对其访问,如果存在右节点则将其入栈,再向左访问子节点,并将其一一入栈,重复上述操作。

非递归后序遍历思路。将根节点入栈,并且一直向左访问子节点,一一入栈,直到为空。然后在出栈前对节点进行访问,如果有右节点,将其入栈,再一直向左访问子节点,重复上述操作。

中序和后序的区别就在于在根节点出栈前后访问入栈子节点

前边说二叉树的时间复杂度为O(logN),这是指一般情况下,或者说是平均复杂度。在极端情况下,二叉树可能会退化成链表,链表查找的事件复杂度为O(logN)明显性能差了很多,所以为了解决这个问题,出现了平衡二叉树。

平衡二叉树

AVL是自平衡二叉搜索树,在AVL中任何节点的两个子树高度差最大为1。当增加或删除之后导致树不在平衡时,需要通过一次或多次旋转再平衡这个树。

简单的讲,左旋就是将自己变为右孩子的左孩子右旋就是将自己变为左孩子的右孩子,两个互为逆操作。

图片的旋转

图左,将Q变为P的右节点,之后再将P原来的右节点变为Q的左节点。

图右,将P变为Q的左节点,之后在将Q原来的左节点变为P的右节点。

这样,在旋转之后中序遍历的结果不变。

前缀树

前缀树是一种有序树,用于保存关联数组,其中的键通常为字符串。

前缀树

可以用于找字符串的最长公共前缀

欢迎关注公众号
扫码关注我的微信公众号-大前端合集
  • 微信公众号-大前端合集