既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
④、队列
队列就好像一段水管一样,两端都是开口的,水从一端进去,然后从另外一端出来。先进去的水先出来,后进去的水后出来。
和水管有些不同的是,队列会对两端进行定义,一端叫队头,另外一端就叫队尾。队头只允许删除操作(出队),队尾只允许插入操作(入队)。
注意,栈是先进后出,队列是先进先出——两者虽然都是线性表,但原则是不同的,结构不一样嘛。
⑤、树
树是一种典型的非线性结构,它是由 n(n>0)个有限节点组成的一个具有层次关系的集合。
之所以叫“树”,是因为这种数据结构看起来就像是一个倒挂的树,只不过根在上,叶在下。树形数据结构有以下这些特点:
每个节点都只有有限个子节点或无子节点;没有父节点的节点称为根节点;每一个非根节点有且只有一个父节点;除了根节点外,每个子节点可以分为多个不相交的子树。下图展示了树的一些术语:
根节点是第 0 层,它的子节点是第 1 层,子节点的子节点为第 2 层,以此类推。
深度:对于任意节点 n,n 的深度为从根到 n 的唯一路径长,根的深度为 0。高度:对于任意节点 n,n 的高度为从 n 到一片树叶的最长路径长,所有树叶的高度为 0。树的种类有很多种,常见的有:
无序树:树中任意节点的子节点之间没有顺序关系。那怎么来理解无序树呢,到底长什么样子?假如有三个节点,一个是父节点,两个是同级的子节点,那么就有三种情况:
假如有三个节点,一个是父节点,两个是不同级的子节点,那么就有六种情况:
三个节点组成的无序树,合起来就是九种情况。
二叉树:每个节点最多含有两个子树。二叉树按照不同的表现形式又可以分为多种。完全二叉树:对于一颗二叉树,假设其深度为 d(d > 1)。除了第 d 层,其它各层的节点数目均已达最大值,且第 d 层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树。
拿上图来说,d 为 3,除了第 3 层,第 1 层、第 2 层 都达到了最大值(2 个子节点),并且第 3 层的所有节点从左向右联系地紧密排列(H、I、J、K、L),符合完全二叉树的要求。
满二叉树:一颗每一层的节点数都达到了最大值的二叉树。有两种表现形式,第一种,像下图这样(每一层都是满的),满足每一层的节点数都达到了最大值 2。
第二种,像下图这样(每一层虽然不满),但每一层的节点数仍然达到了最大值 2。
二叉查找树:英文名叫 Binary Search Tree,即 BST,需要满足以下条件:
任意节点的左子树不空,左子树上所有节点的值均小于它的根节点的值;任意节点的右子树不空,右子树上所有节点的值均大于它的根节点的值;任意节点的左、右子树也分别为二叉查找树。
基于二叉查找树的特点,它相比较于其他数据结构的优势就在于查找、插入的时间复杂度较低,为 O(logn)。假如我们要从上图中查找 5 个元素,先从根节点 7 开始找,5 必定在 7 的左侧,找到 4,那 5 必定在 4 的右侧,找到 6,那 5 必定在 6 的左侧,找到了。
理想情况下,通过 BST 查找节点,所需要检查的节点数可以减半。
平衡二叉树:当且仅当任何节点的两棵子树的高度差不大于 1 的二叉树。由前苏联的数学家 Adelse-Velskil 和 Landis 在 1962 年提出的高度平衡的二叉树,根据科学家的英文名也称为 AVL 树。
平衡二叉树本质上也是一颗二叉查找树,不过为了限制左右子树的高度差,避免出现倾斜树等偏向于线性结构演化的情况,所以对二叉搜索树中每个节点的左右子树作了限制,左右子树的高度差称之为平衡因子,树中每个节点的平衡因子绝对值不大于 1。
平衡二叉树的难点在于,当删除或者增加节点的情况下,如何通过左旋或者右旋的方式来保持左右平衡。
Java 中最常见的平衡二叉树就是红黑树,节点是红色或者黑色,通过颜色的约束来维持着二叉树的平衡:
1)每个节点都只能是红色或者黑色
2)根节点是黑色
3)每个叶节点(NIL 节点,空节点)是黑色的。
4)如果一个节点是红色的,则它两个子节点都是黑色的。也就是说在一条路径上不能出现相邻的两个红色节点。
5)从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
B 树:一种对读写操作进行优化的自平衡的二叉查找树,能够保持数据有序,拥有多于两个的子树。数据库的索引技术里就用到了 B 树。
⑥、堆
堆可以被看做是一棵树的数组对象,具有以下特点:
堆中某个节点的值总是不大于或不小于其父节点的值;堆总是一棵完全二叉树。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
⑦、图
图是一种复杂的非线性结构,由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G 表示一个图,V 是图 G 中顶点的集合,E 是图 G 中边的集合。
上图共有 V0,V1,V2,V3 这 4 个顶点,4 个顶点之间共有 5 条边。
在线性结构中,数据元素之间满足唯一的线性关系,每个数据元素(除第一个和最后一个外)均有唯一的“前驱”和“后继”;
在树形结构中,数据元素之间有着明显的层次关系,并且每个数据元素只与上一层中的一个元素(父节点)及下一层的多个元素(子节点)相关;
而在图形结构中,节点之间的关系是任意的,图中任意两个数据元素之间都有可能相关。
⑧、哈希表
哈希表(Hash Table),也叫散列表,是一种可以通过关键码值(key-value)直接访问的数据结构,它最大的特点就是可以快速实现查找、插入和删除。
数组的最大特点就是查找容易,插入和删除困难;而链表正好相反,查找困难,而插入和删除容易。哈希表很完美地结合了两者的优点, Java 的 HashMap 在此基础上还加入了树的优点。
哈希函数在哈希表中起着常关键的作,它可以把任意长度的输入变换成固定长度的输出,该输出就是哈希值。哈希函数使得一个数据序列的访问过程变得更加迅速有效,通过哈希函数,数据元素能够被很快的进行定位。
若关键字为 k,则其值存放在hash(k)的存储位置上。由此,不需要遍历就可以直接取得 k 对应的值。
对于任意两个不同的数据块,其哈希值相同的可能性极小,也就是说,对于一个给定的数据块,找到和它哈希值相同的数据块极为困难。再者,对于一个数据块,哪怕只改动它的一个比特位,其哈希值的改动也会非常的大——这正是 Hash 存在的价值!
尽管可能性极小,但仍然会发生,如果哈希冲突了,Java 的 HashMap 会在数组的同一个位置上增加链表,如果链表的长度大于 8,将会转化成红黑树进行处理——这就是所谓的拉链法(数组+链表)。
数据结构
数据结构是相互之间存在一种或多种特定关系的数据元素的集合
逻辑结构(分为线性结构和非线性结构)
反映数据元素之间的逻辑关系的数据结构,是针对具体问题的,可以表示成一种或多种存储结构
集合结构(非线性结构)
集合通常是由一组无序的, 不能重复的元素构成 数据结构中的元素之间除了“同属一个集合” 的相互关系外,别无其他关系
线性结构
线性结构是一个有序数据元素的集合,常用的线性结构有:线性表,栈,队列,双队列,数组,串。 非线性结构,其逻辑特征是一个结点元素可能有多个直接前趋和多个直接后继。常见的非线性结构有:二维数组,多维数组,广义表,树(二叉树等)。
线性结构是一个有序数据元素的集合
数组
线性表
0个或多个具有相同类型的数据元素的有限序列
存储结构
顺序存储结构
顺序存储结构,用一段地址连续的存储单元 一次存储线性表的数据元素。比如数组
每个数据元素存数据元素信息外(数据域),还要存储它的后继元素的存储地址(指针域)
优点:
- 无需为表示表中元素之间的逻辑关系而增加额外的存储空间
- 可以快速的存取表中任意位置的元素,时间复杂度为O(1)
缺点:
- 插入和删除操作需要移动大量元素
- 当线性表变化较大时,难以确定存储空间的容量
- 造成存储空间的"碎片"
链式存储结构
用一组任意的存储单元存储线性表的数据元素, 这组存储单元可以是连续的,也可以是不连续的
单链表
链表中每个结点可以包含若干个数据域和若干个指针域。 如果每个结点中只包含一个指针域,则称其为单链表。
优点:
- 单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制
- 插入和删除更快,时间复杂度为O(n),在给出某位置的指针后,复杂度仅为O(1)
缺点:
- 查找效率比顺序存储结构差,时间复杂度为O(n)
静态链表
用数组描述的链表叫静态链表(用数组代替指针)
为了给没有指针的高级语言设计的视线单链表的方法,很少用(虽然java,c#也没有指针,但是引用类型相当于变样实现了指针)
优点: 插入和删除只需要修改游标,无需移动元素 从而改进了在顺序存储结构中的插入,删除移动大量元素的缺点
缺点: 没有解决连续存储分配带来的表长难以确认的问题 失去了顺序存储结构随机存取的特性
循环链表
将单链表中终端结点的指针段由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表就
称为单循环链表,简称循环链表
双向链表
在单链表的每个结点中,再设置一个指向其前驱结点的指针域 (就意味着双向链表的结点都有俩个指针域,一个指向直接后继, 一个指向直接前驱)
栈(特殊的线性表)
限定仅在表尾进行插入和删除操作的线性表,又称后进先出(LIFO)的线性表 (允许插入和删除的一端称为栈顶,另一端称为栈底)
队列(特殊的线性表)
只允许在一端进行插入操作,而另一端进行删除操作的线性表 先进先出(FIFO)
顺序存储结构(顺序队列)
循环队列
链式存储结构(链队列)
串(字符串)
有0个或多个字符组成的有限序列
针对的是字符集,就是说把字符串中多个字符连在一起
存储结构
顺序存储结构
链式存储结构
模式匹配
朴素的描述匹配 (从头开始一个个字符匹配)
效率很低,复杂度为O((n-m+1)*m) n是总的字符串,m是需要匹配的字符串
KMP模式匹配算法
算法证明和更详细的说明,请参阅《算法导论》第2版第32章字符串匹配
KMP模式匹配算法改进
树形结构(非线性结构)
数据元素之间存在一对多的层次关系
数是n(n>=0)个节点的有限集。若n=0,称为空树。树的节点是互不交互的。 + 度:节点拥有的子数(节点)数量称为"度",度为0的称为叶节点。 + 树的度:树的度是树内各节点的度的最大值 + 节点的层次:跟为第一层,一次类推。 + 数的深度:数中节点的最大层次称为"深度"或"高度"
二叉树
特点
- 每个结点最多有俩棵子树
- 左右子树是顺序的,次序不能颠倒
- 即使树中只有一棵子树,也要区分左右
五种形态
- 空二叉树
- 只有一个根结点
- 根结点只有左子树
- 根结点只有右子树
- 根结点既有左子树,又有右子树
性质
在二叉树的第i层上之多有2i-1(i-1是上标)个结点
深度为K的二叉树至多有2k-1(k>=1,k是上表)个结点
特殊二叉树
斜树
- 所有结点都只有左子树的二叉树叫左斜树
- 所有结点都只有右子树的二叉树叫右斜树
满二叉树
一个二叉树中,所有分支结点都存在左子树和右子树, 并且所有叶子都在同一层上,称为满二叉树
完全二叉树
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中 在最左边,这就是完全二叉树。
线索二叉树
每个二叉树左右俩个指针域,如果为空,放着也浪费空间。 所以第一次遍历二叉树时,如果左指针域为空就存前驱地址, 右指针域为空就存后继地址。但是左侧需要一个tag来标识左指 针域存的是左孩子结点还是前驱,右侧也同样需要。
存储结构
顺序存储结构
只用于完全二叉树(因为完全二叉树定义的严格, 可以用顺序结构表示出二叉树的结构,很有优越性。详情参考P172) 该结构不太通用,通用的见二叉链表
二叉链表
二叉树每个结点最多有俩个孩子,所以可以用 一个数据域+俩个指针域这样的结构存储二叉树
遍历
概念
从根结点出发,按照某种次序依次访问二叉树中 所有结点,使得每个结点被访问一次且仅被访问一次
遍历方法(限定了从左到右的习惯)
前序遍历
根结点=>左子树=>右子树 (切记:是先把所有左子树遍历完了,再遍历右子树)
中序遍历
从根结点开始(并不是先访问根结点),遍历根结点的 左子树=>根结点=>右子树
后序遍历
从根结点开始(并不是先访问根结点),遍历根结点的 左子树=>右子树=>根结点
层序遍历(BFS常用)
根结点一层层从上而下遍历
哈夫曼树(也叫最优二叉树)
带权路径长度WPL最小的二叉树称作哈夫曼树
哈夫曼编码
哈夫曼编码实现压缩,解压缩
原理:先构造哈夫曼树,然后对字符串再次编码,二进制的长度会明显缩小, 所以达到了压缩的效果。解压缩也要用哈夫曼树,才能知道哪几个二进制对应哪个字符
图形结构(非线性结构)
数据元素是多对多的关系
概念:有顶点的有穷非空集合和顶点之间边的集合组成 表示为G(V,E),其中G表示一个图,V是图G中顶点的集合,E是边的集合
特点:图中数据元素称为顶点,图中不允许没有顶点
术语
顶点
图中数据元素称为顶点,图中不允许没有顶点
无向边
顶点Vi到Vj(i和j是下标)之间的边没有方向, 则称这条边为无向边,用无序偶对(ViVj)来表示
有向边
顶点Vi到Vj之间的边有方向, 则称这条边为有向边,也称为弧
无向图
图中任意俩个顶点之间的边都是无向边
连通图
概念:从顶点V导顶点V’有路径,称V和V’是连通的。 如果对于图中任意俩个顶点都是连通的则称为连通图 (能连通就行,不一定要相邻)
连通分量
- 要是子图
- 子图要是连通的
- 连通子图还有极大顶点数
- 具有极大顶点数的连通子图包含依附于这些顶点的所有边
生成树
一个连通图的生成树是一个极小的连通子图, 它含有图中全部的n个顶点,但只有足以构成一棵树的n-1条边(p221)
有向图
图中任意俩个顶点之间的边都是有向边
强连通图
概念:如果对于图中任意俩个顶点都是连通的则称为连通图 (能连通就行,不一定要相邻)
强连通分量
参考连通分量定义
有向树
概念:一个有向图恰有一个顶点的入口为0(根节点), 其余顶点的入度均为1,则是一颗有向树
简单图
不存在顶点到其自身的边(自己到自己),且同一条边不重复出现
无向完全图
在无向图中,任意俩个顶点之间都存在边
有向完全图
在有向图中,任意俩个顶点之间都存在方向互为相反的俩条弧网
有的图的边或弧具有与它相关的数字,这叫做权。权可以表示一个顶点到另 一个顶点的距离或者耗费,这种带权的图称为网
存储结构
邻接矩阵
用俩个数组来表示图,一个一维数组存储图中顶点信息, 一个二维数组(邻接矩阵)存储图中的边或弧的信息
缺点
对于边数相对于顶点较少(顶点多,边数少)的图, 这种结构存在存储空间的浪费
邻接表
数组和链表相结合的存储方法称为邻接表
特点
- 图中顶点用一个一维数组存储
- 每个顶点的所有邻接点构成一个新线性表,
- 如果是有向图,还可以建立有向图的逆邻接表,
即对每个顶点vi都建立一个链接为vi为弧头的表。 (可以很容易得到顶点的入度或以顶点为弧头的弧)
优缺点
想了解入度就必须遍历整个图才知道,反之,逆邻接链表解决了入度却不了解出度的情况。俩者不可兼得
十字链表
把邻接表和逆邻接表结合起来
邻接多重表
主要优化无向图
边集数组
俩个一维数组构成,一个存储顶点的信息,一个存储边的信息。 这个边数组每个数据元素由一条边的起点下标,终点下标和权重组成
遍历
深度优先(DFS)
约定原则:在没有碰到重复顶点的情况下,始终向右手边走。 走回到顶点之后,还要按原路一步步返回,在一步步验证是否都都走过了
广度优先(BFS)
图需要变形下,改造成类似树那样有明显的层级关系的样式
最小生成树
概念:我们把构造连通网的最小代价生成树称为最小生成树
所谓最小代价,就是n个顶点,用n-1条边 把一个连通图连接起来,并且使得权值的和最小
算法
普里姆(Prim)算法
以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树
克鲁斯卡尔(Kruskal)算法
以最小权值边开始构建
最短路径
迪杰斯特拉(Dijkstra)算法
一步步求出与顶点的最短路径,过程中都是基于已经求出的最大路径的基础上
佛洛伊德(Floyd)算法
拓扑排序算法
物理结构(存储结构)
数据的逻辑结构在计算机中的存储形式
顺序存储结构
数据元素存放在地址连续的存储单元里, 数据间的逻辑关系和物理关系是一致的 (不方便插入,删除)
不方便插入,删除
链式存储结构
数据元素存放在任意的存储单元里,这组存储单元可以是连续的, 也可以是不连续的 (很灵活,给个指针就能找到。需要一个指针存放数据元素的地址)
很灵活,给个指针就能找到。需要一个指针存放数据元素的地址
索引存储结构
为了方便查找,整体无序,但索引块之间有序,需要额外空间,存储索引表。 优点:对顺序查找的一种改进,查找效率高 缺点:需额外空间存储索引
散列存储结构
选取某个函数,数据元素根据函数计算存储位置可能存在多个数据元素存储在同一位置,引起地址冲 优点:查找基于数据本身即可找到,查找效率高,存取效率高。 缺点:存取随机,不便于顺序查找。
数据运算
查找运算
顺序表查找
顺序查找(线性查找)
从表中第一个(或最后一个)记录开始,逐个进行记录的的关键字和给定值比较。
有序表查找
折半查找(二分查找)
切记:表必须是有序的。mid=(low+high)/2。复杂度是0(logn)
可以优化的地方:每次都从1/2处查找,对于有些场景还是不太适合的, 比如查找am单词,很显然从字典的前面查找效率更高,所以优化点是从哪里开始折半
插值查找
公式:mid=low+(key-a[low])*(high-low)/a[high]-a[low] ;low和high是数组的下标
适合场景:
表长较大,而关键字分配又比较均匀的查找表,性能比折半查找要好得多。复杂度也是0(logn)
斐波那契查找
构造另外一个斐波那契数列用于辅助
公式:mid=low+F[K-1]-1 ;F是斐波那契数列
比较:平均效率优于折半查找,最坏情况下,效率低于折半
线性索引查找
数据集增长非常快的情况下,保证关键字有序,代价很高昂。所以这种数据都是按先后顺序存储。
稠密索引
索引项一定要按照关键码有序的排列
分块索引
把数据集的记录分成了若干块,满足俩个条件
- 块内无序
- 块间有序
倒排索引(P312)
概念:记录号表存储具有相同次关键字的所有记录的记录号 (可以指向记录的指针或者该记录的主关键字)
搜索引擎最基础的搜索技术
二叉搜索树(又称二叉查找树/排序数)
特点:
- 若左子树不为空,则左子树上所有结点值均小于根结点的值
- 若右子树不为空,则右子树上所有结点的值均大于它的根结点的值
- 它的左右子树也分别为二叉排序树
优点:
是一个既使得插入和删除效率不错,又可以比较高效率的实现查找的算法
缺点:
极端情况下,会退化成链表。时间复杂度为O(n)
平衡二叉搜索树(AVL树)
概念:是一种二叉排序树,其中每一个节点 的左子树和右子树的高度差绝对值不超过1
优缺点:
维护这种高度平衡所付出的代价比从中获得的效率收益还大,故而实际的应用不多, 更多的地方是用追求局部而不是非常严格整体平衡的红黑树。 当然,如果应用场景中对插入删除不频繁,只是对查找要求较高,那么AVL还是较优于红黑树。
多路查找树(B树)
概念:每一个结点的孩子树可以多余俩个,且每一个结点处可以存储多个元素
4种形式
2-3树
每一个结点都具有俩个孩子(称为2结点),或三个孩子(称为3结点)
2-3-4树
2-3树的扩展,最多四个孩子
B树
一种平衡的多路查找树
所有叶子结点都位于同一层
B+树
应文件系统那个所需而出的一种B树的变形树
出现在分支节点中的元素会在叶子结点中再次列出,每一个叶子结点都会保存一个指向后一叶子结点的指针
红黑树
概念:一种自平衡二叉查找树,和AVL树类似(并不是真正的平衡二叉树), 都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
适合:适合搜索,插入,删除较多的情况
性质:
每个结点要么是红色,要么是黑色
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
概念:是一种二叉排序树,其中每一个节点 的左子树和右子树的高度差绝对值不超过1
优缺点:
维护这种高度平衡所付出的代价比从中获得的效率收益还大,故而实际的应用不多, 更多的地方是用追求局部而不是非常严格整体平衡的红黑树。 当然,如果应用场景中对插入删除不频繁,只是对查找要求较高,那么AVL还是较优于红黑树。
多路查找树(B树)
概念:每一个结点的孩子树可以多余俩个,且每一个结点处可以存储多个元素
4种形式
2-3树
每一个结点都具有俩个孩子(称为2结点),或三个孩子(称为3结点)
2-3-4树
2-3树的扩展,最多四个孩子
B树
一种平衡的多路查找树
所有叶子结点都位于同一层
B+树
应文件系统那个所需而出的一种B树的变形树
出现在分支节点中的元素会在叶子结点中再次列出,每一个叶子结点都会保存一个指向后一叶子结点的指针
红黑树
概念:一种自平衡二叉查找树,和AVL树类似(并不是真正的平衡二叉树), 都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
适合:适合搜索,插入,删除较多的情况
性质:
每个结点要么是红色,要么是黑色
[外链图片转存中…(img-MObwfLev-1715551900781)]
[外链图片转存中…(img-fecqPDI0-1715551900781)]
[外链图片转存中…(img-MuV6fYoK-1715551900781)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新