feat: 数据结构笔记

master
zr 3 years ago committed by old-tom
parent 5ccfaba2c3
commit 7e056b9686

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@ -0,0 +1,8 @@
+ 数据结构及算法
+ Java基础
+ Spring、Spring boot
+ Docker
+ kafka
+ 数据库
+ mybatis
+ 大数据(hadoop、hive、hbase、sqoop)

@ -0,0 +1,35 @@
### 一、个人介绍
+ 云南楚雄人、从事开发工作有5年公安行业从业4年、财政从业1年。去烽火之前是云南艾拓主要业务早期省厅数据接入与地州科信大数据平台建设德宏。烽火主要在昆明市局负责网安COP15项目与定制化开发。
+ 对公安行业的理解1. 数据量大,用户少-->在做业务系统架构设计时不需要过于复杂 2. 硬件占合同比例高、软件偏少 3. 客户对数据分析能力要求高 4. 客户值班你值班、客户休息你不一定休息
+ 为什么选择面试美亚1. 都是公安行业 2. 之前在市局与省厅(滇仁杰)接触过张贵阳(开发氛围不错)、所红芬、李志兴觉得不错
+ 未来个人规划大数据开发与数据分析类传统开发很快会被低代码平台替代烽火已有自研前端快速开发平台计划明年考PMP及postgresql认证
### 二、离职原因
1. 经常半夜或通宵协助客户处理疫情核查任务导致得肺炎
2. 烽火明年没合同
3. 与个人期望的技术路线不符。在烽火是地方研发中心与总部相差甚远,地方研发中心只相当于运维型开发。
### 三、项目介绍
### 四、技术面试
1. spring
+ 对IOC(控制反转)的理解bean实例化的过程由原来的new变成-->事先创建好后放入容器需要时再取出并且是默认单例模式也可以进行lazyloadbean的生命周期交由容器管理在调用时使用注入即可@Resource和@Autowridebean的生命周期实例化对象-->设置对象属性-->前置处理-->后置处理-->销毁
+ 对AOP的理解基于动态代理技术将共同调用的逻辑日志、事务、权限控制进行封装便于减少重复代码及耦合
+ 对SpringMvc的理解通过贫血模型将数据、逻辑、显示分离解耦
http请求发送-->有dispatcherServlet对请求进行分发-->HandlerMapping根据uri匹配对应的处理器-->Controller-->处理完成后通过视图解析器返回对应视图
+ Spring 中使用的设计模式:
1. 工厂模式Bean工厂、ApplicationContext创建bean对象
2. 代理模式AOP实现
3. 单例模式Spring Bean默认单例
4. 模板方法模式jdbcTemplate
5. 包装器:动态数据源
6. 观察者Spring事件监听
7. 适配器模式Controller
+ Spring事务注解式事务@Transactional及申明式事务
1. 大数据
2. 数据治理
3. 缓存
4. http请求
### 五、期望薪资与最快入职时间
1. 看公积金比例如果是10%13不到10%14
2. 最快入职下周一
### 六、对自己的规划
1. 明年考PMP及postgresql 的认证
2. 希望做大数据开发项目

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

@ -0,0 +1,15 @@
AVL树可以定义为高度平衡二叉搜索树其中每个节点与平衡因子相关联该平衡因子通过从其左子树的子树中减去其右子树的高度来计算。
如果每个节点的平衡因子在`-1`到`1`之间,则称树是平衡的,否则,树将是不平衡的并且需要平衡。
平衡系数(k)=高度(左(k)) - 高度(右(k))
如果任何节点的平衡因子为`1`,则意味着左子树比右子树高一级。
如果任何节点的平衡因子为`0`,则意味着左子树和右子树包含相等的高度。
如果任何节点的平衡因子是`-1`,则意味着左子树比右子树低一级。
可以看到,与每个节点相关的平衡因子介于`-1`和`+1`之间。 因此它是AVL树的一个例子。
![[160613_98775.png]]
### 为什么使用AVL树
通过自平衡解决二叉搜索树查找(搜索)节点问题!!!
AVL树通过不让它倾斜来控制二叉搜索树的高度。 高度为`h`的二叉搜索树中的所有操作所花费的时间
是`O(h)`。 但是,如果二叉搜索树变得偏斜(即最坏的情况),它可以扩展到`O(n)`。 通过将该高度限制为`log n`AVL树将每个操作的上限强加为`O(log n)`,其中`n`是节点的数量。

@ -0,0 +1,23 @@
为弥补红黑树高度不可控问题提出多叉搜索树即为B-树
B树满足一下条件
1. 树中每个节点至多有M个孩子节点即至多有m-1个关键字
2. 除根节点外其他节点至少有m/2个孩子节点
3. 若根节点不是叶子节点则根节点至少有2个孩子节点
4. 所有叶子节点都在同一层上即B树是所有结点的平衡因子均等于0的多路查找树。
如下图所示一颗3阶b树
![[微信截图_20221216171144.png]]
每个节点都会存储key、data、指针(如图5阶B树)
![[1446087-bc023e47bc74cfa1.webp]]
## B-tree的插入
与BST相同比较大小后判断放在左还是右
## B-tree的删除
需要先判断节点是否富有富有删除一个key剩余key的数量大于等于(m/2)向上取整-1。
节点如果不富有需要从兄弟、父亲节点借。如果都不富有只能降低树的高度。具体过程参考B站站长数据结构
B-tree模拟 [B-Tree Visualization (usfca.edu)](https://www.cs.usfca.edu/~galles/visualization/BTree.html)

@ -0,0 +1,13 @@
二叉排序树又称二叉排序树。它或者是一个空树,或者是一个具有下列性质的二叉树:
- 若它的左子树不空,则左子树上所有节点的值均小于它的根结构的值
- 若它的右子树不空,则右子树上所有结点的值均大于它的根节点的值
- 它的左、右子树也分别是二叉排序树
![[20190311150104225.png]]
BST以链接方式存储保持了链接存储结构在执行插入或删除操作时不用移动元素的优点只要找到合适的插入和删除位置后仅需要修改链接指针即可。插入删除的时间性能比较好。而对于BST的查找其比较次数等于给定值的结点在二叉排序树的层数极端情况下最少为1次最多不会超过树的深度。也就是说BST的查找性能取决于BST的形状。
我们希望二叉排序树是比较平衡的,其深度与完全二叉树相同,均为\log_{2}nlog2n + 1那么查找的时间复杂度也就为O(logn)近似于折半查找。这就引申出一个问题即如何让BST**平衡化**。
模拟AVL树插入及自平衡过程
[AVL Tree Visualzation (usfca.edu)](https://www.cs.usfca.edu/~galles/visualization/AVLtree.html)

@ -0,0 +1,10 @@
二叉树是一种特殊类型的通用树,它的每个节点最多可以有两个子节点。 二叉树通常被划分为三个不相交的子集。
- 节点的根
- 左二叉树
- 右二叉树
![[093725_27930.png]]
遍历方式:
前序遍历:从根节点开始向下遍历
中序遍历:从左到右
后序遍历:

@ -0,0 +1,27 @@
伸展树(splay tree)是一颗二叉搜索树它的定义是建立在二叉搜索树之上并且它是基于类似程序局部性原理的假设一个节点在一次被访问后这个节点很可能不久再次被访问。那么伸展树的做法就是在每次一个节点被访问后我们就把它推到树根的位置。正像程序局部性原理的实际效率被广泛证明一样伸展树在实际的搜索效率上也是非常高效的。尽管存在最坏情况下单次操作会花费O(N)的时间但是这种情况并不是经常发生而实际证明伸展树能够保证M次连续操作最多花费O(MlogN)的时间。
相比于平衡二叉树,伸展树有差不多的**平均性能**,其他的优势在于:不需要存储平衡信息。另外如果采用自顶向下的调整方式,还能简略额外的栈开销。
## 伸展树的旋转
#### 一、单R
![[20151102155743401.png]]
什么叫单R型呢在上图中我们查找的元素是9,其父节点是7并且7是根结点查找结点是其父节点的右孩子而且把9变成根结点只需一次左旋转即可即将9提升一层这样的情况我们叫单R型经过一次左旋转后结点9替代了原来的根结点7变成新的根结点注意这里因为图简单9最终变成了根结点在树复杂的情况一般不会一次就变成了根结点但肯定会变成原子树的根这也就是程序中说的当前子树中的新根
#### 二、单L
![[20151102155639325.png]]
单L型和单R型是对称的也就是说查找结点3是其父节点的左子树并且其父节点是根结点这样一次右旋转后3就是根结点了。
#### 三、双R
![[20170904224242553.png]]
所谓RR型简单点说就是两次R型两次左旋转这种情况是查找结点有父节点同时也有祖父结点并且三则在同右侧这种就是RR型针对这种情况先把查找结点的父节点旋转一次即提升一层然后再以查找结点再次旋转这样查找结点就到了根结点了都是左旋转只是旋转对象不一样罢了。
#### 四、双L
![[20151102160109880.png]]
#### 五、RL
![[20151102160900703.png]]
#### 六、LR
![[20151102160736300.png]]

@ -0,0 +1,9 @@
单链表是一种链式存取的数据结构用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以节点来表示的每个节点的构成data域数据元素+next域下一个结点的存储位置
单链表与数组相比的最大差别是:单链表的数据元素存放在内存空间的地址是不连续的,而数组的数据元素存放的地址在内存空间中是连续的,这也是为什么根据索引无法像数组那样直接就能查询到数据元素。
对于单链表的这种特殊结构,我们可以用“火车”来类比,假设一节车厢可以存储一个数据元素,当数据不够时,就新增一节车厢挂载在火车尾。在遍历时,只能从头部车厢开始遍历,依次走到尾部(即单向遍历,默认从前向后)
![[Pasted image 20221207183805 1.png]]
总结1.只能在队尾添加元素,并且只能从头部开始遍历 2.在内存中的地址是随机非连续的 3.每个节点都必须记录下个节点的存储位置
难点1.如何查找上一个节点,需要从头开始遍历,下标-1 2. 如何插入节点需要找到找到上一个节点将上一个节点的NEXT节点作为待插入节点的NEXT节点然后将待插入节点作为上一个节点新的NEXT节点

@ -0,0 +1,7 @@
为什么引入双链表单链表的结点中只有一个指向其后继的指针使得单链表要访问某个结点的前驱结点时只能从头开始遍历访问后驱结点的复杂度为O(1)访问前驱结点的复杂度为O(n)。为了克服上述缺点,引入了双链表。
单向链表查找的方向只能是一个方向,而双向链表可以向前或者向后查找;单链表如果想要实现删除操作,需要找到待删除节点的前一个节点。而双向链表可以实现自我删除
![[104421_43592.png]]
![[104543_51020.png]]

@ -0,0 +1,12 @@
用途:用于数据传输过程中,将信息转换为二进制后进行**编排**,可以在一定程度上减少信息传输的大小。
定义带权路径长度WPL最短的二叉树
### 一、基本概念
路径:从树中一个结点到另一个节点之间的分支构成这两个结点间的路径
路径长度:两结点间路径上的分支数
树的路径长度:从树根到每一个结点的路径长度之和
权:将树中结点赋给一个有某种含义的数值,则这个数值成为该结点的权
结点的带权路径长度:从根结点到该节点之间的路径长度与该节点的权的乘积
树的带权路径长度:树中所有叶子结点的带权路径长度之和。
树的带权路径长度越小可以认为性能越好

@ -0,0 +1,31 @@
可以理解为由数组实现的完全二叉树,所有它没有使用父指针或者子指针。堆根据“堆属性”来排序,“堆属性”决定了树中节点的位置。
堆的常用方法:
- 构建优先队列
- 支持堆排序
- 快速找出一个集合中的最小值(或者最大值)
堆分为两种:最大堆和最小堆,两者的差别在于节点的排序方式。
在最大堆中_父节点的值比每一个子节点的值都要大_。在最小堆中_父节点的值比每一个子节点的值都要小_。这就是所谓的“堆属性”并且这个属性对堆中的每一个节点都成立
堆存在下标属性公式:
parent(i)=floor((i-1)/2) 向下取整
left(i)=2i+1
right(i)=2i+2
**插入操作**:以最大堆为栗子,插入其实就是把插入结点放在堆最后面,然后与父亲比较,如果父亲值小于它,那么它就和父亲结点交换位置,重复该过程,直到插入节点遇到一个值比它大的父亲或者它成为树根结点
以最大堆为栗子在堆中插入值为20的结点红色结点代表新进入
![[20161207183935000.png]]
20明显大于它的父亲结点值所以和7交换位置交换后新的父亲值还是比它小继续交换
![[微信截图_20221213114347.png]]
一步一步与它前面比它小的父亲结点交换位置最后20成为根结点
最小堆同理,只不过要求父亲结点要比它小,如果父亲结点大于它,就得交换。
**删除操作**
删除就是删除最大堆中的最大值或者最小堆中的最小值,也就是树根
以删除最大堆树根为例子,删除其实就是整个堆中少了一个结点,不妨把位于最后面的一个结点当成新的树根,然后与它左右孩子比较,与值最大并且值大于它的孩子进行交换(好好读这句话),直到它的孩子都是小于它的,或者变成树叶。
用最大堆为例删除树根20
![[20161207184700681.png]]![[20161207185133520.png]]
把最后的结点8提到树根然后就按说明步骤找到一个位置它的孩子都小于它或者他变成树叶。
![[20161207185210411.png]]

@ -0,0 +1,11 @@
堆栈(Stack)是一个有序列表,它只能在顶端执行插入和删除。
堆栈(Stack)是一个递归数据结构,具有指向其顶部元素的指针。
堆栈有时被称为后进先出(LIFO)列表,即首先插入堆栈的元素将最后从堆栈中删除。
栈的应用:递归、表达式评估和转换、解析、浏览器、编辑器、树遍历
栈的三个操作:推入(入栈)、弹出(出栈)、窥视(遍历)
栈的2种实现方式基于数组静态栈、基于链表动态栈
![[微信截图_20221209171247.png]]

@ -0,0 +1,31 @@
树的概念:
- 树是一种递归数据结构,包含一个或多个数据节点的集合,其中一个节点被指定为树的根,而其余节点被称为根的子节点。
- 除根节点之外的节点被划分为非空集,其中每个节点将被称为子树。
- 树的节点要么保持它们之间的父子关系,要么它们是姐妹节点。
- 在通用树中,一个节点可以具有任意数量的子节点,但它只能有一个父节点。
- 下图显示了一棵树,其中节点`A`是树的根节点,而其他节点可以看作是`A`的子节点。
![[132046_67706.png]]
#### 基本术语
- **根节点** 根节点是树层次结构中的最顶层节点。 换句话说,根节点是没有任何父节点的节点。
- **子树** 如果根节点不为空,则树`T1``T2`和`T3`称为根节点的子树。
- **叶节点** 树的节点,没有任何子节点,称为叶节点。 叶节点是树的最底部节点。 一般树中可以存在任意数量的叶节点。 叶节点也可以称为外部节点。
- **路径** 连续边的序列称为路径。 在上图所示的树中,节点`E`的路径为`A→B→E`。
- **祖先节点** **节点的祖先是从根到该节点的路径上的任何前节点**。根节点没有祖先节点。 在上图所示的树中,节点`F`的祖先是`B`和`A`。
- **度** 节点的度数等于子节点数,节点数。 在上图所示的树中,节点`B`的度数为`2`。叶子节点的度数总是`0`,而在完整的二叉树中,每个节点的度数等于`2`。
- **级别编号** 为树的每个节点分配一个级别编号,使得每个节点都存在于高于其父级的一个级别。树的根节点始终是级别`0`。
#### 树的类型
1. 一般树:一般树(_General Tree_)按层次顺序存储元素,其中顶级元素始终以`0`级作为根元素。 除根节点之外的所有节点都以级别数存在。 存在于同一级别的节点称为兄弟节点,而存在于不同级别的节点表现出它们之间的父子关系。 节点可以包含任意数量的子树。 每个节点包含`3`个子树的树称为三元树。
2. 森林:可以将森林(_Forests_)定义为可以通过删除根节点并将根节点连接到第一级节点的边缘来获得的不相交树的集合。
![[140125_30358.png]]
3. 二叉树:二叉树是一种数据结构,其中每个节点最多可以有`2`个子节点。 存在于最顶层的节点称为根节点。 具有`0`个子节点的节点称为叶节点。 二叉树用于表达式评估等应用程序。
4. 二叉搜索树:二叉搜索树是有序二叉树。 左子树中的所有元素都小于根,而右子树中存在的元素大于或等于根节点元素。 二进制搜索树用于计算机科学领域的大多数应用,如搜索,排序。
5. 表达树:表达式树用于评估简单的算术表达式。表达式树基本上是二叉树,其中内部节点由运算符表示,而叶节点由操作数表示。表达式树被广泛用于解决代数表达式
![[140359_43916.png]]
6. 竞赛树:竞赛树用于记录两名比赛者之间每轮比赛的胜者。 比赛树也可以称为选择树或获胜者树。 外部节点表示正在播放匹配的比赛者,而内部节点表示所播放的匹配的胜者。 在最顶层比赛的获胜者作为树的根节点出现。例如在4个比赛者之间进行的比赛树如下所示。 但是,左子树中的获胜者将与右子树的获胜者对战。
![[140708_58672.png]]

@ -0,0 +1,52 @@
红黑树是一种含有红黑结点并能自平衡的二叉查找树。它必须满足下面性质:
- 性质1每个节点要么是黑色要么是红色。
- 性质2根节点是黑色。
- 性质3每个叶子节点NIL是黑色。
- 性质4每个红色结点的两个子结点一定都是黑色。
- 性质5任意一结点到每个叶子结点的路径都包含数量相同的黑结点。
- 最长子树长度不超过最短子树的2倍
从性质5又可以推出
- 性质5.1:如果一个结点存在黑子结点,那么该结点肯定有两个子结点
- **左旋**:以某个结点作为支点(旋转结点)其右子结点变为旋转结点的父结点右子结点的左子结点变为旋转结点的右子结点左子结点保持不变。如图3。
- **右旋**:以某个结点作为支点(旋转结点)其左子结点变为旋转结点的父结点左子结点的右子结点变为旋转结点的左子结点右子结点保持不变。如图4。
- **变色**:结点的颜色由红变黑或由黑变红。
![[2392382-a95db442f1b47f8a.webp]]
![[2392382-0676a8e2a12e2a0b.webp]]
## 查找:
- 从根结点开始查找,把根结点设置为当前结点;
- 若当前结点为空返回null
- 若当前结点不为空用当前结点的key跟查找key作比较
- 若当前结点key等于查找key那么该key就是查找目标返回当前结点
- 若当前结点key大于查找key把当前结点的左子结点设置为当前结点重复步骤2
- 若当前结点key小于查找key把当前结点的右子结点设置为当前结点重复步骤2
![[2392382-07b47eb3722981e6.webp]]
## 插入:
插入操作包括两部分工作:一查找插入的位置;二插入后自平衡。查找插入的父结点很简单,跟查找操作区别不大:
1. 从根结点开始查找;
2. 若根结点为空,那么插入结点作为根结点,结束。
3. 若根结点不为空,那么把根结点作为当前结点;
4. 若当前结点为null返回当前结点的父结点结束。
5. 若当前结点key等于查找key那么该key所在结点就是插入结点更新结点的值结束。
6. 若当前结点key大于查找key把当前结点的左子结点设置为当前结点重复步骤4
7. 若当前结点key小于查找key把当前结点的右子结点设置为当前结点重复步骤4
注:新插入的节点一定是红色
![[2392382-7521866b50683a24.webp]]
![[2392382-fa2b78271263d2c8.webp]]
## 删除:
红黑树的删除操作也包括两部分工作:一查找目标结点;而删除后自平衡。查找目标结点显然可以复用查找操作,当不存在目标结点时,忽略本次操作;当存在目标结点时,删除后就得做自平衡处理了。删除了结点后我们还需要找结点来替代删除结点的位置,不然子树跟父辈结点断开了,除非删除结点刚好没子结点,那么就不需要替代。
二叉树删除结点找替代结点有3种情情景
- 情景1若删除结点无子结点直接删除
- 情景2若删除结点只有一个子结点用子结点替换删除结点
- 情景3若删除结点有两个子结点用后继结点大于删除结点的最小结点替换删除结点
![[2392382-fa2b78271263d2c8 1.webp]]

@ -0,0 +1,28 @@
## 一、数据结构
1. 单链表(带头结点、不带头结点)设计与实现(增删改查),双链表设计与实现
2. 栈设计与实现(数组和链表),队列设计与实现(数组和链表)
3. 二叉树概念学习,二叉树前序、中序、后序遍历递归、非递归实现 ,层序遍历
4. 二叉排序树设计与实现(插入删除)
5. 堆(优先队列、堆排序)
6. AVL(平衡)树设计与实现(四种自旋方式理解实现)
7. 伸展树、红黑树原理概念理解
8. B、B+原理概念理解
9. 哈夫曼树原理概念理解(贪心策略)
10. 哈希(散列表)原理概念理解(几种解决哈希冲突方式)
11. 并查集/不相交集合(优化和路径压缩)
12. 图论拓扑排序
13. 图论dfs深度优先遍历、bfs广度优先遍历
14. 最短路径Dijkstra算法、Floyd算法、spfa算法
15. 最小生成树prim算法、kruskal算法
16. 其他数据结构线段树、后缀数组等等
## 二、经典算法
1. 递归算法(求阶乘、斐波那契、汉诺塔问题)
2. 二分查找
3. 分治算法(快排、归并排序、求最近点对等问题)
4. 贪心算法(使用较多,区间选点问题,区间覆盖问题)
5. 常见动态规划(LCS(最长公共子序列) LIS(最长上升子序列)背包问题等等)
6. 回溯算法(经典八皇后问题、全排列问题)
7. 位运算常见问题(参考剑指offer和LeetCode问题)
8. 快速幂算法(快速求幂乘、矩阵快速幂)
9. kmp等字符串匹配算法
10. 一切其他数论算法(欧几里得、拓展欧几里得、中国剩余定理等等)
Loading…
Cancel
Save