数据结构和算法
2022-07-30 21:06:13   1  举报             
     
         
 AI智能生成
  数据结构总结
    作者其他创作
 大纲/内容
  动态规划    
     实战    
     新的硬币找零问题。假设我们有⼏种不同币值的硬币
v1,v2,……,vn(单位是元)。如果我们要⽀付w元,求最少需要多少个硬币。⽐如,我们有3种不同的硬币,1元、3元、
5元,我们要⽀付9元,最少需要3个硬币(3个3元的硬币)。
    v1,v2,……,vn(单位是元)。如果我们要⽀付w元,求最少需要多少个硬币。⽐如,我们有3种不同的硬币,1元、3元、
5元,我们要⽀付9元,最少需要3个硬币(3个3元的硬币)。
 0/1 背包问题  
     如何量化两个字符串的相似度?  
     如何编程计算莱⽂斯坦距离?  
     如何编程计算最⻓公共⼦串⻓度?
  
     我们有⼀个数字序列包含n个不同的数字,如何求出这个序列中的最⻓递增⼦序列⻓度?⽐如2, 9, 3, 6, 5, 1, 7这样⼀组数字序
列,它的最⻓递增⼦序列就是2, 3, 5, 7,所以最⻓递增⼦序列的⻓度是4。
    列,它的最⻓递增⼦序列就是2, 3, 5, 7,所以最⻓递增⼦序列的⻓度是4。
 0-1背包问题升级版  
     淘宝的“双⼗⼀”购物节有各种促销活动,⽐如“满200元减50元”。假设你⼥朋友的购物⻋中有n个(n>100)想买的商品,她希望从⾥⾯选⼏个,在凑够满减条件的前提下,让选出来的商品价格总和最⼤程度地接近满减条件(200元),这样就可以极⼤限度地“薅⽺⽑”。  
     理论  ⼀个模型三个特征    
     什么是“⼀个模型”?它指的是动态规划适合解决的问题的模型。我把这个模型定义为“多阶段决策最优解模
型”。
    型”。
 1.最优⼦结构
最优⼦结构指的是,问题的最优解包含⼦问题的最优解。反过来说就是,我们可以通过⼦问题的最优解,推导出问题的最优
解。如果我们把最优⼦结构,对应到我们前⾯定义的动态规划问题模型上,那我们也可以理解为,后⾯阶段的状态可以通过前
⾯阶段的状态推导出来。
    最优⼦结构指的是,问题的最优解包含⼦问题的最优解。反过来说就是,我们可以通过⼦问题的最优解,推导出问题的最优
解。如果我们把最优⼦结构,对应到我们前⾯定义的动态规划问题模型上,那我们也可以理解为,后⾯阶段的状态可以通过前
⾯阶段的状态推导出来。
 2.⽆后效性
⽆后效性有两层含义,第⼀层含义是,在推导后⾯阶段的状态的时候,我们只关⼼前⾯阶段的状态值,不关⼼这个状态是怎么
⼀步⼀步推导出来的。第⼆层含义是,某阶段状态⼀旦确定,就不受之后阶段的决策影响。⽆后效性是⼀个⾮常“宽松”的要
求。只要满⾜前⾯提到的动态规划问题模型,其实基本上都会满⾜⽆后效性。
    ⽆后效性有两层含义,第⼀层含义是,在推导后⾯阶段的状态的时候,我们只关⼼前⾯阶段的状态值,不关⼼这个状态是怎么
⼀步⼀步推导出来的。第⼆层含义是,某阶段状态⼀旦确定,就不受之后阶段的决策影响。⽆后效性是⼀个⾮常“宽松”的要
求。只要满⾜前⾯提到的动态规划问题模型,其实基本上都会满⾜⽆后效性。
 3.重复⼦问题
这个概念⽐较好理解。前⾯⼀节,我已经多次提过。如果⽤⼀句话概括⼀下,那就是,不同的决策序列,到达某个相同的阶段
时,可能会产⽣重复的状态。
    这个概念⽐较好理解。前⾯⼀节,我已经多次提过。如果⽤⼀句话概括⼀下,那就是,不同的决策序列,到达某个相同的阶段
时,可能会产⽣重复的状态。
 解题思路    
     1.状态转移表法  
     2.状态转移⽅程法  
     分治思想    
     分治算法(divide and conquer)的核⼼思想其实就是四个字,分⽽治之 ,也就是将原问题划分成n个规模较⼩,并且结构与
原问题相似的⼦问题,递归地解决这些⼦问题,然后再合并其结果,就得到原问题的解。
    原问题相似的⼦问题,递归地解决这些⼦问题,然后再合并其结果,就得到原问题的解。
 MapRedue的本质就是分治算法    
     MapReduce框架只是⼀个任务调度器,底层依赖GFS来存储数据,依赖Borg管理机器。它从GFS中拿数据,交给
Borg中的机器执⾏,并且时刻监控机器执⾏的进度,⼀旦出现机器宕机、进度卡壳等,就重新从Borg中调度⼀台机器执⾏。
    Borg中的机器执⾏,并且时刻监控机器执⾏的进度,⼀旦出现机器宕机、进度卡壳等,就重新从Borg中调度⼀台机器执⾏。
 ⼀台机器过于低效,那我们就把任务拆分到多台机器上来处理。如果拆分之后的⼩任务之间互不⼲扰,独⽴计算,最后再将结
果合并。这不就是分治思想吗?
    果合并。这不就是分治思想吗?
 实战    
     O(n)时间复杂度内求⽆序数组中的第K⼤元素。  
     如何编程求出⼀组数据的有序对个数或者逆序对个数呢?  
     ⼆维平⾯上有n个点,如何快速计算出两个距离最近的点对?  
     有两个n*n的矩阵A,B,如何快速求解两个矩阵的乘积C=A*B?  
     分治思想在海量数据处理中的应⽤  
     迭代和递归    
     递归--数学归纳法    
     递归需要满⾜的三个条件    
     1.⼀个问题的解可以分解为⼏个⼦问题的解  
     2.这个问题与分解之后的⼦问题,除了数据规模不同,求解思路完全⼀样  
     3.存在递归终⽌条件  
     写递归代码最关键的是写出递推公式,找到终⽌条件  
     跳台阶问题  
     迭代---遍历  
     基本排序算法    
     概念
    
     稳定性。这个概念是说,如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变。  
     原地排序(Sorted in place)。原地排序算法,就是特指空间复杂度是O(1)的排序算法。  
     插入    
     原地排序,稳定的  
     将数组中的数据分为两个区间,已排序区间和未排序区间。初始已排序区间只有⼀个元素,就是数组的第⼀个元
素。插⼊算法的核⼼思想是取未排序区间中的元素,在已排序区间中找到合适的插⼊位置将其插⼊,并保证已排序区间数据⼀
直有序。重复这个过程,直到未排序区间中元素为空,算法结束。
    素。插⼊算法的核⼼思想是取未排序区间中的元素,在已排序区间中找到合适的插⼊位置将其插⼊,并保证已排序区间数据⼀
直有序。重复这个过程,直到未排序区间中元素为空,算法结束。
 选择    
     原地排序,不稳定的  
     选择排序算法的实现思路有点类似插⼊排序,也分已排序区间和未排序区间。但是选择排序每次会从未排序区间中找到最⼩的
元素,将其放到已排序区间的末尾。
    元素,将其放到已排序区间的末尾。
 冒泡    
     原地排序,不稳定的  
     冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进⾏⽐较,看是否满⾜⼤⼩关系要求。如果不满⾜就
让它俩互换。⼀次冒泡会让⾄少⼀个元素移动到它应该在的位置,重复n次,就完成了n个数据的排序⼯作。
    让它俩互换。⼀次冒泡会让⾄少⼀个元素移动到它应该在的位置,重复n次,就完成了n个数据的排序⼯作。
 归并    
     非原地排序,稳定的  
     如果要排序⼀个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排
序,再将排好序的两部分合并在⼀起,这样整个数组就都有序了。
    序,再将排好序的两部分合并在⼀起,这样整个数组就都有序了。
 快排    
     原地排序,不稳定的  
     如果要排序数组中下标从p到r之间的⼀组数据,我们选择p到r之间的任意⼀个数据作为pivot(分区点)。我们遍历p到r之间的数据,将⼩于pivot的放到左边,将⼤于     pivot的放到右边,将pivot放到中间。根据分治、递归的处理思想,我们可以⽤递归排序下标从p到q-1之间的数据和下标从q+1到r之间的数据,直到区间缩⼩为1,就说明所有的数据都有序了。  
     优化快排    
     1.三数取中法,2.随机法
  
     桶排序    
     非原地排序,稳定的  
     ⼼思想是将要排序的数据分到⼏个有序的桶⾥,每个桶⾥的数据再单独进⾏排序。桶内排完序之后,再把每个桶⾥的数据按照顺序依次取出,组成的序列就是有序的了。  
     如何根据年龄给100万⽤户数据排序  
     贪心算法    
     哈夫曼编码利⽤贪⼼算法来实现对数据压缩编码,有效节省数据存储空间的。    
     霍夫曼编码不仅会考察⽂本中有多少个不同字符,还会考察每个字符出现的频率,根据频率的不同,选择不同⻓度的编码。霍
夫曼编码试图⽤这种不等⻓的编码⽅法,来进⼀步增加压缩的效率。如何给不同频率的字符选择不同⻓度的编码呢?根据贪⼼
的思想,我们可以把出现频率⽐较多的字符,⽤稍微短⼀些的编码;出现频率⽐较少的字符,⽤稍微⻓⼀些的编码。
    夫曼编码试图⽤这种不等⻓的编码⽅法,来进⼀步增加压缩的效率。如何给不同频率的字符选择不同⻓度的编码呢?根据贪⼼
的思想,我们可以把出现频率⽐较多的字符,⽤稍微短⼀些的编码;出现频率⽐较少的字符,⽤稍微⻓⼀些的编码。
 霍夫曼编码是不等⻓的,每次应该读取1位还是2位、3位等等来解压缩呢?这个问题就导致霍夫曼编码解压缩起来⽐较复杂。为了避免解压缩过程中的歧义,霍夫曼编码要求各个字符的编码之间,不会出现某个编码是另⼀个编码前缀的情况。  
     假设我有⼀个包含1000个字符的⽂件,每个字符占1个byte(1byte=8bits),存储这1000个字符就⼀共需要8000bits,那有没
有更加节省空间的存储⽅式呢?
    有更加节省空间的存储⽅式呢?
 实战    
     1.分糖果
我们有m个糖果和n个孩⼦。我们现在要把糖果分给这些孩⼦吃,但是糖果少,孩⼦多(m
    我们有m个糖果和n个孩⼦。我们现在要把糖果分给这些孩⼦吃,但是糖果少,孩⼦多(m
 2.钱币找零
这个问题在我们的⽇常⽣活中更加普遍。假设我们有1元、2元、5元、10元、20元、50元、100元这些⾯额的纸币,它们的张
数分别是c1、c2、c5、c10、c20、c50、c100。我们现在要⽤这些钱来⽀付K元,最少要⽤多少张纸币呢?
    这个问题在我们的⽇常⽣活中更加普遍。假设我们有1元、2元、5元、10元、20元、50元、100元这些⾯额的纸币,它们的张
数分别是c1、c2、c5、c10、c20、c50、c100。我们现在要⽤这些钱来⽀付K元,最少要⽤多少张纸币呢?
 3.区间覆盖
假设我们有n个区间,区间的起始端点和结束端点分别是[l1, r1],[l2, r2],[l3, r3],……,[ln, rn]。我们从这n个区间中选出⼀
部分区间,这部分区间满⾜两两不相交(端点相交的情况不算相交),最多能选出多少个区间呢?
    假设我们有n个区间,区间的起始端点和结束端点分别是[l1, r1],[l2, r2],[l3, r3],……,[ln, rn]。我们从这n个区间中选出⼀
部分区间,这部分区间满⾜两两不相交(端点相交的情况不算相交),最多能选出多少个区间呢?
 4. 在⼀个⾮负整数a中,我们希望从中移除k个数字,让剩下的数字值最⼩,如何选择移除哪k个数字呢?  
     2. 假设有n个⼈等待被服务,但是服务窗⼝只有⼀个,每个⼈需要被服务的时间⻓度是不同的,如何安排被服务的先后顺
序,才能让这n个⼈总的等待时间最短?
    序,才能让这n个⼈总的等待时间最短?
 字符串匹配    
     暴力破解  
     KMP算法等难理解  
     回溯思想    
     回溯的处理思想,有点类似枚举搜索。我们枚举所有的解,找到满⾜期望的解。为了有规律地枚举所有可能的解,避免遗漏和
重复,我们把问题求解的过程分为多个阶段。每个阶段,我们都会⾯对⼀个岔路⼝,我们先随意选⼀条路⾛,当发现这条路⾛
不通的时候(不符合期望的解),就回退到上⼀个岔路⼝,另选⼀种⾛法继续⾛。
    重复,我们把问题求解的过程分为多个阶段。每个阶段,我们都会⾯对⼀个岔路⼝,我们先随意选⼀条路⾛,当发现这条路⾛
不通的时候(不符合期望的解),就回退到上⼀个岔路⼝,另选⼀种⾛法继续⾛。
 实战    
     8皇后问题  
     0-1背包  
     正则表达式  
     二分查找算法    
     基本形式    
     ⼆分查找针对的是⼀个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对⽐,将待查找的区间缩⼩为之前的⼀半,直到找到要查找的元素,或者区间被缩⼩为0。O(logn)惊⼈的查找速度  
     如何在1000万个整数中快速查找某个整数?  
     注意    
     ⼆分查找依赖的是顺序表结构,简单点说就是数组。针对的是有序数据。数据量太⼩不适合⼆分查找,,数据量太⼤也不适合⼆分查找。
  
     变体    
     变体⼀:查找第⼀个值等于给定值的元素  
     变体⼆:查找最后⼀个值等于给定值的元素  
     变体三:查找第⼀个⼤于等于给定值的元素  
     变体四:查找最后⼀个⼩于等于给定值的元素  
     如何快速定位出⼀个IP地址的归属地?  
     哈希算法    
     将任意⻓度的⼆进制值串映射为固定⻓度的⼆进制值串,这个映射的规则就是哈希算法,⽽通过原始数据映射之后得到的⼆进制值串就是哈希值。  
     应用    
     应⽤⼀:安全加密    
     最常⽤于加密的哈希算法是MD5(MD5 Message-DigestAlgorithm,MD5消息摘要算法)和SHA(Secure Hash Algorithm,安全散列算法)。  
     应⽤⼆:唯⼀标识    
     如果要在海量的图库中,搜索⼀张图是否存在,我们不能单纯地⽤图⽚的元信息(⽐如图⽚名称)来⽐
对,因为有可能存在名称相同但图⽚内容不同,或者名称不同图⽚内容相同的情况。那我们该如何搜索呢?
    对,因为有可能存在名称相同但图⽚内容不同,或者名称不同图⽚内容相同的情况。那我们该如何搜索呢?
 应⽤三:数据校验    
     BT下载  
     应⽤四:散列函数  
     区块链    
     区块链是⼀块块区块组成的,每个区块分为两部分:区块头和区块体。
区块头保存着 ⾃⼰区块体 和 上⼀个区块头 的哈希值。
因为这种链式关系和哈希值的唯⼀性,只要区块链上任意⼀个区块被修改过,后⾯所有区块保存的哈希值就不对了。
区块链使⽤的是 SHA256 哈希算法,计算哈希值⾮常耗时,如果要篡改⼀个区块,就必须重新计算该区块后⾯所有的区块的哈
希值,短时间内⼏乎不可能做到
    区块头保存着 ⾃⼰区块体 和 上⼀个区块头 的哈希值。
因为这种链式关系和哈希值的唯⼀性,只要区块链上任意⼀个区块被修改过,后⾯所有区块保存的哈希值就不对了。
区块链使⽤的是 SHA256 哈希算法,计算哈希值⾮常耗时,如果要篡改⼀个区块,就必须重新计算该区块后⾯所有的区块的哈
希值,短时间内⼏乎不可能做到
 在分布式中应用    
     应⽤五:负载均衡    
     如何才能实现⼀个会话粘滞(session sticky)的负载均衡算法呢?也就是说,我们需要在同⼀个客户端上,在⼀次会话中的所有请求都路由到同⼀个服务器上。  
     应⽤六:数据分⽚    
     1.如何统计“搜索关键词”出现的次数?  
     2.如何快速判断图⽚是否在图库中?  
     应⽤七:分布式存储    
     ⼀致性哈希算法    
     子主题  
     将哈希空间 [0, 2n-1] 看成一个哈希环,每个服务器节点都配置到哈希环上。每个数据对象通过哈希取模得到哈希值 之后,存放到哈希环中顺时针方向第一个大于等于该哈希值的节点上。  
     虚拟节点    
     一致性哈希存在数据分布不均匀的问题,节点存储的数据量有可能会存在很大的不同。
数据不均匀主要是因为节点在哈希环上分布的不均匀,这种情况在节点数量很少的情况下尤其明显。
解决方式是通过增加虚拟节点,然后将虚拟节点映射到真实节点上。虚拟节点的数量比真实节点来得多,那么虚拟节
点在哈希环上分布的均匀性就会比原来的真实节点好,从而使得数据分布也更加均匀。
    数据不均匀主要是因为节点在哈希环上分布的不均匀,这种情况在节点数量很少的情况下尤其明显。
解决方式是通过增加虚拟节点,然后将虚拟节点映射到真实节点上。虚拟节点的数量比真实节点来得多,那么虚拟节
点在哈希环上分布的均匀性就会比原来的真实节点好,从而使得数据分布也更加均匀。
 在负载均衡应⽤中,利⽤哈希算法替代映射表,可以实现⼀个会话粘滞的负载均衡策略。在数据分⽚应⽤中,通过哈希算法对
处理的海量数据进⾏分⽚,多机分布式处理,可以突破单机资源的限制。在分布式存储应⽤中,利⽤⼀致性哈希算法,可以解
决缓存等分布式系统的扩容、缩容导致数据⼤量搬移的难题。
    处理的海量数据进⾏分⽚,多机分布式处理,可以突破单机资源的限制。在分布式存储应⽤中,利⽤⼀致性哈希算法,可以解
决缓存等分布式系统的扩容、缩容导致数据⼤量搬移的难题。
 数组    
     数组(Array)是⼀种线性表数据结构。它⽤⼀组连续的内存空间,来存储⼀组具有相同类型的数据。  
     容器和数组的比较    
     ArrayList最⼤的优势就是可以将很多数组操作的细节封装起来。⽐如前⾯提到的数组插⼊、删除数据时需要搬移
其他数据等。另外,它还有⼀个优势,就是⽀持动态扩容。
    其他数据等。另外,它还有⼀个优势,就是⽀持动态扩容。
 为什么⼤多数编程语⾔中,数组要从0开始编号,⽽不是从1开始呢?    
     从数组存储的内存模型上来看,“下标”最确切的定义应该是“偏移(offset)”。前⾯也讲到,如果⽤a来表示数组的⾸地址,a[0]
就是偏移为0的位置,也就是⾸地址,a[k]就表示偏移k个type_size的位置,所以计算a[k]的内存地址只需要⽤这个公式:
但是,如果数组从1开始计数,那我们计算数组元素a[k]的内存地址就会变为:
ArrayList users = new ArrayList(10000);
for (int i = 0; i < 10000; ++i) {
users.add(xxx);
}
a[k]_address = base_address + k * type_size
对⽐两个公式,我们不难发现,从1开始编号,每次随机访问数组元素都多了⼀次减法运算,对于CPU来说,就是多了⼀次减
法指令。   
    就是偏移为0的位置,也就是⾸地址,a[k]就表示偏移k个type_size的位置,所以计算a[k]的内存地址只需要⽤这个公式:
但是,如果数组从1开始计数,那我们计算数组元素a[k]的内存地址就会变为:
ArrayList
for (int i = 0; i < 10000; ++i) {
users.add(xxx);
}
a[k]_address = base_address + k * type_size
对⽐两个公式,我们不难发现,从1开始编号,每次随机访问数组元素都多了⼀次减法运算,对于CPU来说,就是多了⼀次减
法指令。
 链表    
     链表通过“指针”将⼀组零散的内存块串联起来使⽤,常用链表结构 单链表、双向链表和循环链表
  
     快慢指针,哨兵机制(头),指针(引用),警惕指针丢失,边界处理,举例画图辅助思考等编码技巧
  
     解决问题    
     循环链表的约瑟夫问题  
     基于链表实现LRU缓存淘汰算法    
     https://crossoverjie.top/JCSprout/#/algorithm/LRU-cache  
     练习    
     单链表反转
链表中环的检测
两个有序的链表合并
删除链表倒数第n个结点
求链表的中间结点
    链表中环的检测
两个有序的链表合并
删除链表倒数第n个结点
求链表的中间结点
 散列表    
     图示结构           
     散列表⽤的是数组⽀持按照下标随机访问数据的特性,所以散列表其实就是数组的⼀种扩展,由数组演化⽽来。可以说,如果
没有数组,就没有散列表。
    没有数组,就没有散列表。
 散列函数    
     散列函数,顾名思义,它是⼀个函数。我们可以把它定义成hash(key),其中key表示元素的键值,hash(key)的值表示经过散
列函数计算得到的散列值。
    列函数计算得到的散列值。
 散列冲突    
     即便像业界著名的MD5、SHA、CRC等哈希算法,也⽆法完全避免这种散列冲突。  
     1.开放寻址法,2.链表法  
     如何设计散列函数    
     散列函数的设计不能太复杂
  
     散列函数⽣成的值要尽可能随机并且均匀分布  
     定义装载因⼦阈值,并且设计动态扩容策略;  
     选择合适的散列冲突解决⽅法。  
     实现    
     Word⽂档中单词拼写检查功能是如何实现的?  
     LinkedHashMap是通过双向链表和散列表这两种数据结构组合实现的。LinkedHashMap中
的“Linked”实际上是指的是双向链表,并⾮指⽤链表法解决散列冲突。
    的“Linked”实际上是指的是双向链表,并⾮指⽤链表法解决散列冲突。
 树    
     二叉树    
     分类    
     满二叉树    
     叶⼦节点全都在最底层,除了叶⼦节点之外,每个节点都有左右两个⼦节点,这种⼆叉树就叫作满
⼆叉树。
    ⼆叉树。
 完全⼆叉树    
     叶⼦节点都在最底下两层,最后⼀层的叶⼦节点都靠左排列,并且除了最后⼀层,其他层的节点个数都要
达到最⼤,这种⼆叉树叫作完全⼆叉树。
    达到最⼤,这种⼆叉树叫作完全⼆叉树。
 堆    
     堆是⼀个完全⼆叉树;
堆中每⼀个节点的值都必须⼤于等于(或⼩于等于)其⼦树中每个节点的值。
    堆中每⼀个节点的值都必须⼤于等于(或⼩于等于)其⼦树中每个节点的值。
 应用    
     堆的应⽤⼀:优先级队列    
     1.合并有序⼩⽂件
  
     2.⾼性能定时器  
     堆的应⽤⼆:利⽤堆求Top K  
     堆的应⽤三:利⽤堆求中位数  
     ⼆叉查找树    
     ⼆叉查找树要求,在树中的任意⼀个节点,其左⼦树中的每个节点的值,都要⼩于这个
节点的值,⽽右⼦树节点的值都⼤于这个节点的值。
    节点的值,⽽右⼦树节点的值都⼤于这个节点的值。
 平衡二叉树    
     AVL树  
     红黑树  
     遍历    
     前序遍历是指,对于树中的任意节点来说,先打印这个节点,然后再打印它的左⼦树,最后打印它的右⼦树。  
     中序遍历是指,对于树中的任意节点来说,先打印它的左⼦树,然后再打印它本身,最后打印它的右⼦树。  
     后序遍历是指,对于树中的任意节点来说,先打印它的左⼦树,然后再打印它的右⼦树,最后打印这个节点本身。  
     层遍历  
     多叉树    
     B树           
     B+树  
     字典树/Trie/前缀树    
     图示    
     子主题  
     代码    
     leetcode 208. 实现 Trie (前缀树)  
     leetcode 820. 单词的压缩编码  
     图    
     相关概念    
     图中的元素我们就叫作顶点(vertex)。图中的⼀个顶点可以与任意其他顶点建⽴连接关系。我们把这种建⽴的关系叫作边(edge)。  
     度(degree),就是跟顶点相连接的边的条数。  
     在有向图中,我们把度分为⼊度(In-degree)和出度(Out-degree)。
顶点的⼊度,表示有多少条边指向这个顶点;顶点的出度,表示有多少条边是以这个顶点为起点指向其他顶点。
    顶点的⼊度,表示有多少条边指向这个顶点;顶点的出度,表示有多少条边是以这个顶点为起点指向其他顶点。
 带权图(weighted graph)。在带权图中,每条边都有⼀个权重(weight)  
     存储⽅法
    
     邻接矩阵    
     如果我们存储的是稀疏图(Sparse Matrix),也就是说,顶点很多,但每个顶点的边并不多,那邻接矩阵的存储⽅法
就更加浪费空间了。⽐如微信有好⼏亿的⽤户,对应到图上就是好⼏亿的顶点。但是每个⽤户的好友并不会很多,⼀般也就三
五百个⽽已。如果我们⽤邻接矩阵来存储,那绝⼤部分的存储空间都被浪费了。
    就更加浪费空间了。⽐如微信有好⼏亿的⽤户,对应到图上就是好⼏亿的顶点。但是每个⽤户的好友并不会很多,⼀般也就三
五百个⽽已。如果我们⽤邻接矩阵来存储,那绝⼤部分的存储空间都被浪费了。
 邻接表    
     每个顶点对应⼀条链表,链表中存储的是与这个顶点相连接的其他顶点。(有点像散列表)  
     遍历    
     广度优先遍历BFS    
     从图中的某一个顶点Vi触发,访问此顶点后,依次访问Vi的各个为层访问过的邻接点,然后分别从这些邻接点出发,直至图中所有顶点都被访问到。广度优先遍历类似树的层序遍历。  
     它其实就是一种“地毯式”层层推进的搜索策略,即先查找离起始顶点最近的,然后是次近的,依次往外搜索。    
     子主题  
     深度优先遍历DFS    
     走迷宫:假设你站在迷宫的某个岔路口,然后想找到出口。你随意选择一个岔路口来走,走着走着发现走不通的时候,你就回退到上一个岔路口,重新选择一条路继续走,直到最终找到出口。这种走法就是一种深度优先搜索策略。    
     子主题  
     从图中某个顶点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到  
     问题    
     如何存储微博、微信等社交⽹络中的好友关系?  
     https://www.cnblogs.com/polly333/p/4760275.html  
     跳表    
     图示结构    
     理解为索引  
     这种链表加多级索引的结构,就是跳表。  
     Redis中的有序集合是通过跳表来实现的  
     队列    
     先进后出队列    
     先进者先出,这就
是典型的“队列”。
    是典型的“队列”。
 循环队列    
     有效的处理一般队列的数据搬移问题  
     最关键的是,确定好队空和队满的判定条件。  
     阻塞队列和并发队列    
     阻塞队列其实就是在队列基础上增加了阻塞操作。简单来说,就是在队列为空的时候,从队头取数据会被阻塞。因为此时还没
有数据可取,直到队列中有了数据才能返回;如果队列已经满了,那么插⼊数据的操作就会被阻塞,直到队列中有空闲位置后
再插⼊数据,然后再返回。
    有数据可取,直到队列中有了数据才能返回;如果队列已经满了,那么插⼊数据的操作就会被阻塞,直到队列中有空闲位置后
再插⼊数据,然后再返回。
 线程安全的队列我们叫作并发队列  
     优先级队列    
     大根堆  
     小根堆  
     栈    
     后进者先出,先进者后出,这就是典型的“栈”结构。  
     ⽐较经典的⼀个应⽤场景就是函数调⽤栈。  
     如何实现浏览器的前进、后退功能?其实,⽤两
个栈就可以⾮常完美地解决这个问题。
    个栈就可以⾮常完美地解决这个问题。
 位图     
     bigMap位图算法    
     所谓bitmap,是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况。通常是用来判断某个数据存不存在的。  
     算法思想: 将大数据量经过hash映射保存到一个bit数组 中,大大减小了存储空间  
     Bloom Filter 布隆过滤器    
     布隆过滤器的原理是,当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。  
     用于高效检测数据元素是否在给的集合中,是BigMap的扩展  
     鉴别垃圾邮件,URL白名单和黑名单过滤  
     布隆过滤器    
     https://snailclimb.gitee.io/javaguide/#/docs/dataStructures-algorithms/data-structure/bloom-filter  
     并查集    
     https://zhuanlan.zhihu.com/p/93647900  
     并查集被很多OIer认为是最简洁而优雅的数据结构之一,主要用于解决一些元素分组的问题。它管理一系列不相交的集合,并支持两种操作。    
     合并(Union):把两个不相交的集合合并为一个集合。  
     查询(Find):查询两个元素是否在同一个集合中。  
     子主题  
    
 
 
 
 
  0 条评论
 下一页