随看随记
Asymptotics
本意是渐近的意思:这里代指当参数为无穷大时,所需要进行运算的次数,和我们常说的复杂度差不多。
- 在一个算法中有很多种不同的运算,可以计算出复杂度,但是我们一般通过计算自增的次数,来计算复杂度。
- 仅仅考虑最坏的情况
- 选择一个代表运算符(这里是选用了自增作为代表运算符)
- 忽略低阶项
- 忽略复杂的常数
复杂度 θ
- N^m 、e^N 、 lnN 是三个不同的复杂度,不同复杂度之间是可以乘积的,但是相加时,e^N> N > lnN
复杂度 O
Disjoint Sets(不相交集)
简述
- 同根即为相连
- 连接不同的items 查看两个item 是否相连。
- 示例
QuickFindDS
- ListOfSetsDS是搜索整个set集,把这个item和目标item放到一个集中,来进行两个item的连接。判断是否在一个集中,来判断是否连接。
- QuickFindDS值相当于有了一个id作为标识,有相同标识的两个item是连接状态。但是将两个item连接还是需要遍历整个数组。
Quick Union
-
将id数组转化成parent数组,从父节点id作为标识,判断是否属于一个集中。
-
parent数组这里储存的是item的父节点的标识,-1标识根路径,后面依次加一,标识在这个树下存在链接。
-
-
-
一个item只有一个父节点,但是可以有很多个子节点。
-
在同一个根里,就是相连的
-
Weighted Quick Union
- 在这里以weight为优先,操作时会直接对两个树的树根进行操作,将一个树的树根直接连接到另一个树的树根,但是这样也导致了其深度会很深,效率不高,因此不推荐使用。
- weighted quick union的高度是Θ(log N,因为每次增加一个树的高度,都需要相同规模的树来进行合并,才能增加树的深度。
Weighted Quick Union with Path Compression and Summary
-
路径压缩就是把所有的要连接的item,及其父节点都连接到root上。下面组图表示15和10相连。
-
-
-
-
其中α(N) 表示反阿克曼函数,具体是啥我也不知道,但是增长很慢,可以当作常数处理。
-
Asymptotics II
- 虽然其在跳,但是其在2N和(1/2)N之间,因此其复杂度为N
Tree Recursion
- 通过树形递归,递归里的两次相加是指数类型的复杂度。
二分查找(Binary Search)
-
复杂度log2N
-
-
对于上面来说有一个bug,在第二行。对于最大加最小再除以二是有风险的行为,有可能会导致溢出。因此最好的方法是这样
int mid = low + ((high - low) / 2);
//为了提高运行速率 也可以这样写
int mid = (low + high) >>> 1;
- 溢出问题写的比较好的一个博客
- 这个博客没有写负数的部分,当负数的部分溢出时,不论是>>,还是>>>都是错误的
- 二分查找法的树形解释
Merge Sort
- 其核心是这张图,对于俩个数组进行合并后排序,其运行时长仍然为N。
- 合并排序是将一个大数组进行原子化分割,分割以后进行合并排序。
- N+N/2+N/4+N/4+N+N/8+…=NlogN
- 先看看视频里有没有写合并排序的代码,如果没有,后面自己找一下。
ADTs, Sets, Maps, BSTs
BST Binary Search Trees 二叉搜索树
- 树有关的定义
- 二叉搜索树和二叉树的区别,BST需要右节点大于左节点(通过上面的演化过程可知),但是二叉树不需要。
- 二叉搜索树需要完整的,可传递的,非对称的。
BST Operation
Insert
Delete
- No Children 直接删除glut对象,并且进行gc。
- One Children 把dog右连接到elf 然后把flat 进行gc
- Two Children
以删除dog为例。找到其上一任或下一任的节点,在这里一定是cat或者elf,从上面的从链表的演化图可得。然后直接将cat或者elf替换掉dog就可以了。
Summary
- Sets 和 Maps 主要区别在于Maps不仅仅储存了对象(key),其还储存了(value)。
BST
BST Tree Height
- 当Tree只有一个分支时,其会退化成LinkedList
- O(N) 意味着小于 二叉搜索树的复杂度小于N和N^2,这两句话没毛病。
BTS Performance
- 在随机的情况下,其有很大的可能会直接变成丰满的二叉搜索树,其复杂度会尽可能接近于Θ(logN),但是在不随机的情况下,会有可能变成List其复杂度会接近Θ(N)。
- 当插入的顺序改变时,原本在一条线上的item,会从一边变到另一边。如图所示
B Tree
[B Tree 与 B+Tree][https://www.jianshu.com/p/ac12d2c83708]
-
从二叉树中过来时,为了避免将二叉搜索树由于在某个节点处增加多个节点而导致退化成链表,因此将其插入到一个一节点中,在同一个节点包含多个值,逐渐向B 树演化。
-
B Tree ,B 再叶子节点处不仅仅拘泥于只有一个值,其可以存放多个值。
-
但是当一个节点处的叶子过于冗余时 将其中间的一个值 放入父节点中 通过其数值的大小关系来进行排序等操作
-
一般对于什么时候判定为冗余,一般是人为规定的。在上图中将允许的长度设置为3,因此将叶子节点书为4的其中一个值放到了其父节点中。
-
当其进行进一步发展,其root节点也变得十分冗余时,会再成立一个新的节点,将这个节点作为树的新root节点。继续向上拆分。
-
对于B 树来讲 有L = 3的树也叫2-3-4树 有L=2的树 也叫2-3树。是因为当L=3时 其节点的下属节点可有做多不超过四个节点,可以是2、3和4的时候,因此成为2-3-4树。同样L=2的树也是如此命名。
-
当L=2或3时,用作平衡搜索树,增加搜索效率。当L非常大有几千的时候,其通常作为数据库的存储结构。
-
2-3树的最好的情况和最差的情况
- Runtime = O(LlogN)
Red Black Tree
- 左旋转增加了树的高度,右旋转降低了树的高度。
缺点
- 同一个节点的数据类型不同,2节点和3节点的相互转换和分割节点。
- 下面是逻辑代码
树的旋转
- 旋转操作都是对其目标节点,及其子节点进行操作,不涉及到其父节点。
树的左旋转 rotateLeft(G)
- 左旋转是将G与右边子节点(P)进行合并,然后根据大小关系,把P放到G的父节点上,成为P的左子节点。P原来的左节点连接到G,右节点连接到P。
- 将G作为旋转点,左旋转是逆时针,右旋转是顺时针,旋转其子节点。
- GP合并,P下属k和r节点也成为PG节点的子节点,然后将P节点升级,成为G的父节点同时r节点成为P的子节点,k按兵不动。
- 就是原P和k以及r节点升级。并根据大小关系,r>P>G、P>k>G。因此根据这层大小关系将树转化为最右面的图。
- 即P和r直接升级,k成为p的右节点。
树的右旋转 rotateRight ( P )
- 参考左旋转,将P与其左子节点合并,并进行相同的操作。
- 对上述已经旋转过的树进行右旋转,你会发现它变回去了。
- 把P变成G的右节点,把k并入P的左节点。是左旋转的逆过程。
通过旋转来平衡树
- 将一个普通的树转化成BST。
- 在3右旋转降级时,2依靠大小关系,和1重新连接,树的枝干是不会出现中断的。
- 如何把一个普通的树转化成BST
红黑树的定义
Glue nodes
- 建立虚拟节点,来转换成BST。
左倾红黑二叉搜索树LLRB
- 对于这中方法来说,黑表示原有的连接,红表示多值节点变换后的连接。
- 左倾红黑二叉搜索树LLRB,其本质是将点给一个节点有多个值时,把右值放到当前节点上,把其左值放到其左子节点上,将原来的中子节点与新左子节点相接。
- 当一个节点有三个值的时候,其是转化成LLRBST的高度变化最大的时候,是2H+1高度。即在P,N,M都是两个值的节点的时候。
- 每条路上的红色连接数不同,但是经过转换后的黑色链接数不变。
Red Black Trees Insertion
红黑树的插入问题
- 在E<S的情况下
- 在E>S的情况下,实现红黑树,需要有一步左旋转。
- 四节点时的插入情况
- 插入之后进行旋转操作将其插入的叶部进行旋转,得到一个新的树
- 对新的树进行颜色旋转,将根部的两个红色连接旋转到其上方
3. 把B进行左旋转
- Conclusion
额外练习
- 答案
- 其主要在于分叉红连接转化成黑连接,父连接转化成红连接。如果没有父连接,仅仅将红连接转化成黑连接就可以了。
Summary
- LLRB Runtime
- 树的高度,(第二个没看懂),插入操作的复杂度
- LLRB实现的逻辑代码
- 讲过的三种树的优劣势
Hashing(哈希化)
- 其最开始的目的是把对象按照一定的规则转化成int类型并保存在地址中,并用在此处设为true,从而认为是一个对象。
其过程的原因是
- 将字符串转化成十进制数字出现了ASCII
- 为了将不同语言文字的字符串也转化成十进制数字出现了溢出
- 为了解决溢出 出现了Hash Code
将英语单词通过27进制,转化成10进制
Hash Table
- 其想法就是当盒子的数目大于鸽子的数目时,就必然导致至少有一个格子要生活两个鸽子。
- 将多余的项目放置到同一个格子中来实现存储
- 对于每一个格子中,其可以使用的数据类型有很多,可以是ArrayList,linkedList,等等
Hash Table的resize 和 负载因子
解释一下
- M表示有多少个格子 图中是4个。
- N表示一共有多少个项目所有绿色的
- 对M进行重新编排叫做重组
- 对是否进行重新编排的依据是N/M的大小,当其超过1.5的时候,将M扩容到两倍,和ArrayList扩容是一样的。。
resize问题
- 当系数超过1.5的时候,将对象进行重新编组,存放到新的Hash Table中。
Hash Tables in Java
-
不要存储能够改变的对象在HashSet 和 HashMap中
-
不要在没有重写HashCode 的情况下重写equals方法
Good Hash Functions
- Java8中的HashCode Function。用了base31编码,因为其不用考虑重复,并且编码规则越小,计算效果越好。
- 31的好处,不会栈溢出,计算花费少
Summary
- 数据被转换哈希码
- 哈希码转换成指标,用于对存储位置的判断
- 数据被存放在指标码中的各自红
- 当负载银子超过某个常数时,对N进行重新划分。
- 当items被广泛的存储,非常好的情况下,会获得平均Θ(1)的运行时间。
Heaps and PQs
Priority Queue(优先队列)
- 在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。
- 添加项目
- 获得最小的项目
- 移除最小的项目
- 尺寸
heaps 堆
- 二叉最小堆保证其子节点第一是大于其父节点的,并且保证左节点满员。图中绿色的两个是堆,但是红色的不是,第三个不满足左满员,第四个则是5>4不符合规则。
- 这个不是二叉最小堆是因为右侧缺一层,如果不缺这一层,就是了
heap operation
add
- 在理论上的位置添加item,然后根据其与父节点的关系,进行和父节点之间的item调换,最终找到正确的位置。
removeSmallest
- 在理论上最后一个item删除自己并成为根节点,然后向原来被删除的地方下沉,直到下沉到合理的位置。
Tree Represention (树的表示方法)
-
链表式
-
-
-
不相交集式
-
- 当其顺序存储,仅仅用一个数组即可表示一棵树。(堆的简单实现原理)
-
Priority Queue Implementation
- 优先队列的实现,其依据堆的方法,进行实现。
Summary All The Data Struction
- 各种数据结构的操作
- 不同数据结构的实现方式,蓝色便是常用,粉色便是不推荐,红色表示及其不推荐。
- 在无序集合中(Set&Map),使用红黑树(包括B Tree、左倾红黑树(LLRB))和Hash Table(图中的HT)两大种
- 在有序集合中(List),以链表和数组表为多。(LinkedList & ArrayList)
- 对于优先队列来说(PQ),以堆(上述的×和/2的数组)和平衡树(上浮下沉的树)为主。
- java的数据结构分类大概
Tries
使用tris进行存储
- 通过空白节点,表示这是存储字母的开始,蓝色节点表示可以是节点的结尾。例如 “a” 和 “awls”
The DataIndexedCharSet Tries
- 因为在items中都已经有了字母,因此不需要再使用一个成员变量来特意存储
- 其运行时间仅仅和单词的长度有关,因此其为查询时间为常数。
针对其内存使用较多进行的改进
- 将items的数组结构换成hashtable数据类型,得到如下图
- 将items的数组结构换成BST数据类型,得到如下图
- 计算性能
- 二叉树和hash table 节省内存但是慢。
Prefix
-
通过建立一个colHelp的函数来帮忙找前缀
-
在colHelp中a、awls、sad、sam、same、sap取出成为检索结果以后, 则剩余的s 和 sa 就是其前缀
-
-
-
Autocomplete
- 在每一个node都有一个数值,这个数值表示当前这个字符串的数字,在最前面有一个最优的字符串数字,
Conclusion
Multidimensional Data(多维数据)
多维数据转化
类比HashTable
- 网格划分
- 将原有的不太好描述的位置,通过给整个图做划分使得其在占有其中一个位置,进行表述
类比Tree
- 将其中的一个属性作为二叉树的排序属性,对整个多维数组进行排序。
2D Date
四叉树 QuadTree Range Finding
- 针对空间问题,将其划分成四个区域,在四个区域中进行类似树的连接
对于查找是否在该点在目标矩形框内,主要分成两步骤
- 查看当前点是否在目标区域 如果不在,则目标区域在的方向
- 如果在,先将该点放入结果集中,然后将其四个领域都查看是否有点在区域中
- 对以上操作进行递归
KD Date(高维数据)
- 对于一般的实际物体来说不会超过3D,但是对于对事物的要求来讲是可以有很多的,如下图所示。
KD Tree
交叉比较
- 单数层 比较左侧数值,复数层比较右侧数值。即颜色加重的数字就是该层要比较的数字
K-D Nearest Find
如何在k-d Tree中找到和(0,7)最近的点
步骤 (说的不太清楚 看 完整版看 Multidimensional Data, Video 7)
- 计算目标点和初始点的距离,并根据单层和双层的需要比较的数和目标点进行比较。
- 进入目标领域,重复步骤一,如果在同一个区域内有多个点,就计算距离,取最小的。 作为最佳值
- 然后要开始考虑在不是最佳情况下是否也会出现最佳值。因此慢慢对原来认为不是最好的区域进行排查。其比较的条件是要比第一个最小值要小。
K-D Tree 伪代码
Summary
Intro to Graphs
Tree
- 定义是Tree有无数个节点组成,两个节点之间必须有且只能有一个连接。
- 从上到下,从左到右遍历
树的深度优先遍历 Traverslas
- 前序遍历
- 中序遍历
- 后序遍历
- 逆时针读取方法
- 后序遍历的应用
- 辅助计算文件夹的大小,通过得到文件的大小,进行相加得到中间文件夹的大小。
Graph
Graph type
- 图的分类
- 图的术语
- Vertice——顶点——node
- edge——边——顶点对
- adjacency——邻接——一个边两端的顶点
- label——权重——weight
- path——路径——依次遍历顶点序列之间的边所形成的轨迹
- cycle——循环——cyclic
- 如果两个顶点之间有路径,就表示两个顶点之间有连接
Graph Problem
- S-T路径:点S和T之间有路径吗
- 连通性:如果路径是相通的,那么会有一条路径贯通所有的点吗
- 双连通性:是否有一个顶点的移除会断开图的连接?
- 最短S-T路径:点S和T之间的最短路径是哪一个
- 循环检测:图中包含几个循环
- 欧拉路径:存在一个循环使用每一个边仅一次吗
- Hamiton路径:存在一个循环使用每一个点仅一次吗
- 平面度:
- 同构:存在两个图是同构的吗。
S-T连接性
- 当一个点已经遍历过以后会被标记,当进入下一个点以后,仅仅会对未标记的点进行便利,而不会返回到为便利的点导致死循环。
- 当在连接3的时候,3并不连接7,因此返回false。退回4,4也不连接,退回5,5向前遍历到6,与7相连接成功,返回True
DepthFirstPaths DFSpath
- 深度优先路径,其重点是在其下一个点中记录上一个点的位置,通过这样的记录,如果返回false的话,可以慢慢返回寻找可以向下遍历的点,继续进行遍历,直到找到7,返回true。如果没有找到的话就返回false,没找到。
Tree vs Graph Traversals
- 3开头是遍历以后从后面开始进行输出
- Summary
BST and Graph Algorithm Implementations
BreadthFirstPaths (广度优先遍历)
- distTo用来记录追踪的顺序,是遍历到的第几个
- edgeTo是用来记录,其上一个遍历的点是哪一个点
- 同时将其标志位True,以表示标记过
Graph API
- 对于API来讲,API的效率包括运行过程,内存使用和实现多种图算法的难度
- 通过使用Map来进行权重和内容的映射
Graph Representations and Graph Algorithm Runtimes
- 没太看懂,以后有时间再搜索一下吧
Graph Traversal Runtimes
- 深度优先遍历
- 广度优先遍历实现代码
- adj方法得到的是遍历v周围的节点,从再进行遍历的时候,随着后面的点慢慢进入队列,队列的迭代也会变多,也因此会把整个图都会遍历到。
Layers of Abstraction
Summary
Graph Shortest Paths
Summary So Far :DFS VS. BFS
- 两个都可以使用再所有的图中
- 输出质量
- 时间效率
- 空间复杂度
- 深度优先遍历使用栈
2.广度优先遍历使用队列
Dijkstra’s Algorithm
- 在寻找从起点到所有终点的最短路径的过程中,可以发现其结果可以被转化成一棵树,而不再是一堆数组。树上的每一个节点都记录了其每个节点到起点的最短距离。
- 最短路径树(Shortest Paths Tree)
- 对于最短路径树来讲,树的节点数为E-1,因为必须有一个为输入点。
- 利用了类似深度优先算法(dfs)算法,得到了一个不带有权重的深度优先的最优解,但是在有权重的条件下,这是错误的。
Dijkstra Algorithm
- 首先,将处了起始点以外的所有点,压入PQ(优先队列)中,通过遍历,将
- 在下方的优先队列中左边的数字表示是哪一个节点,右边的数字表示到起始点的距离。
- 在入优先队列以后,优先队列会根据距离进行重新排序,在最前面的会被弹出,并对其后续节点进行进一步遍历
- 算法包括两个部分:1. 入PQ,按顺序依次进行迭代,弹出和操作。2. 对于距离更短的情况来说,更新数值,直至迭代结束。
- 该算法中包含的数据结构有很多,其中很重要的是edgeTo[v],distTo[v],和PQ。edgeTo[v]是储存其从开始点到该点的距离。distTo[v]是统计其上一个点是从哪里过来的。
Dijkstra’s Correctness and Runtime
- 这个算法的有点事保证了正确性,因为在计算以后的距离比原来大的情况下,他是不会改变的。
- Dijkstra算法不适用边长为负数的情况,因为如果为负数:假如一张图里有一个总长为负数的环,那么Dijkstra算法有可能会沿着这个环一直绕下去,绕到地老天荒。。。
A*
-
A*是D~算法在AI的延伸,其也是通过优先队列进行操作,但是其排序的原则不一样,其是通过一种学习算法,进行辅助排序,而不是和原来一样的根据算的权重进行排序。
-
-
没太听明白 看看这个链接吧
Summary
Minimum Spanning Trees
Spanning Trees
- Spanning Trees的三个属性
- 各个点之间是联通的
- 没有循环
- 包含了所有的顶点
MST(Minimum Spanning Trees) VS SPT(Shortest Path Trees)
-
SPT是有出发点的,出发点不同,其SPT也会不同,但是MST和出发点无关,但是在某些特殊情况下,SPT和MST是一样的
-
-
-
在这个图中是不可能出现MST和SPT恰好相同的情况,因为对于中心右上的点来说SPT一定是走2权重的路径,但是MST则不会走这条路径,因为这会导致整体的权重增加。
-
the cut property
- cut将所有的点分割成两大部分
- crossing edge 不同颜色的点连接的边
- 最短的crossing edge一定在MST内
- 算法的大概思想
- 找到一个没有crossing edge 的cut 点集 在MST
- 寻找到最小的的crossing edge 并将其添加到MST中
- 重复剩下的所有边
prims algorithm conceptually
- 算法大概步骤
- 随机选定一个起始点 将其自己划分成一个cut 其余划分成另一个cut
- 在这两个cut中寻找最短crossing edge ,其一定是MST中的一个边
- 将边的两个点放到一个set中,成为一个cut
- 重复上述步骤,直至所有的点都在一个set中
- 照片中的# 表示图中的所有店 edgeTo表示和其相连接的另一个点
- 在实现时,通常会使用PQ,来对最小的距离进行排序
- 从起始点开始,有两个边更新后进行排序
- 1<2 ,所以remove 2 点,保留1点在后面进行排序
- 同时跟进1 的三个边 更新 1的三个边另一端点的距离,继续放到PQ中排序
- 最短的被remove掉,其余的如果路径比原路径小的就更新,比原路径大的就保持不变。
- 直到最后
- 看到这里其实和SPT很像,但是不同的是prim只比较这一点附近的数值,而SPT是比较的从起始点开始一路加起来的数值
prims vs dijkstras
- prims 和 dijkstras很像,但是不同的是prim只比较这一点附近的数值,而dijkstras是比较的从起始点开始一路加起来的数值
kruskals algorithm
- 其算法的特点是把所有的路径都列出来,根据路径的大小从小到大进行排序。
- 并且从小到大建立连接,其能否建立连接判断条件是是否会产生循环。
- 接下来一步一步,将所有的点都建立起来,就结束了。
WQU 是将已经union的点连在一起,判断是否会产生循环,以及构建出MST
kruskals runtime
Reductions and Decomposition
- 和图有关的大部分算法都和DFS相关
Topological Sorting(拓扑排序)
- 拓扑排序的结构是Postorder DFS(后序DFS结果的反序)
- 拓扑排序有点像根据路径大小进行排序的广度优先遍历。DJ算法是深度优先遍历
Shortest Paths on DAGs(directed acyclic gragh 有向循环图)
- 下面的拓扑图是这个图的另一种表示方法,把这个图所有的点都横过来就是下面的图
- 其整个算法结构类似于广度优先遍历
- 从0开始有两个箭头,进行遍历
- 然后对3的两个边进行遍历,先走哪个边都是可以的
- 等到遇到了4,有数值冲突时,进行大小判定
- 然后一路遍历,最后结束
- 其能够应对负数权重是因为这个算法将其冲突点的所有上游的点,边全部遍历过了,已经是最终的数值,不会因为有负数而对后面的计算造成冲突。而DJ算法是基于深度优先遍历的,在冲突点右数值改变时会造成后面的点也有冲突,从而失败。
Longest Paths
- 如何找最长路径,将所有的边的权重变成负数,同时使用拓扑算法,找最小的数值就可以了。