遍历
概念
从根结点出发,按照某种次序依次访问二叉树中 所有结点,使得每个结点被访问一次且仅被访问一次
遍历方法(限定了从左到右的习惯)
前序遍历
根结点=>左子树=>右子树 (切记:是先把所有左子树遍历完了,再遍历右子树)
中序遍历
从根结点开始(并不是先访问根结点),遍历根结点的 左子树=>根结点=>右子树
后序遍历
从根结点开始(并不是先访问根结点),遍历根结点的 左子树=>右子树=>根结点
层序遍历(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树类似(并不是真正的平衡二叉树), 都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
适合:适合搜索,插入,删除较多的情况
性质:
每个结点要么是红色,要么是黑色
根结点永远是黑色
所有的叶节点都是空结点(即null),并且是黑色的
每个红色结点的俩个子结点都是黑色(从每个叶子到跟的路径上不会有俩个连续的红色结点)
从任一结点到其子树中每个叶子结点的路径都包含相同数量的黑色结点
关键性质:
这些性质强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。主要原因在于,性质4导致了路径不能有两个毗连的红色节点,最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点,根据性质5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长
散列表查找(哈希表)
概念:散列技术是在记录的存储位置和它的关键字之间建立一个稳定的对于关系f, 使得每个关键字key对于一个存储位置f(key),f称为散列函数,又称为哈希(Hash)函数
特点
在存储时,通过散列函数计算记录的散列地址,并按此散列地址存储该记录
查找记录时,我们通过同样的散列函数计算记录的散列地址,按此散列地址访问该记录
缺点
有时候俩个关键字不同,但是算出来的地址相同,称为冲突
散列函数构造方法
直接定址法
数字分析法
平方取中法
折叠法
除留余数法
随机数法
散列冲突的解决方法
开放定址法
一个冲突,就去寻找下一空的散列函数
再散列函数法
准备多个散列函数,有冲突就换一个
链地址法
公共溢出区法
冲突的都单独存储到溢出表中
排序运算
概念
内排序与外排序
内排序是在排序整个过程中,待排序的所有记录都放置在内存中。外排序是由于排序的记录太多, 不能同时放置在内存,整个排序过程需要在内外存之间多次交换数据才能进行
排序种类
冒泡排序
复杂度O(n2) 2是上标
正宗的冒泡排序是相邻元素俩俩比较
冒泡排序优化
加个flag,如果后面后面已经是有序的了,就不需要再继续后面的循环判断了
简单选择排序
每个元素依次和后面所有的元素比较大小
直接插入排序
将一个记录插入到已经排好序的有序表中,从而得到一个新的记录数+1的有序表
希尔排序
把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;虽则增量逐渐减少, 每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组
堆排序
利用堆这种数据结构所设计的一种排序算法
归并排序
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序
快速排序
通过一次排序将待排序记录分割称独立的俩部分,其中一部分记录的关键字均比另一部分小, 则可分别堆这俩部分记录继续进行排序,以达到整个序列有序的目的
算法
算法是解决特定问题求解步骤的描述。
时间复杂度(大O表示法)
推导方法
\1. 用常数1取代运行时间汇总的所有加法常数
\2. 在修改后的运行次数函数中,只保留最高阶
\3. 如果最高阶项存在且不是1,则去除与这个项相乘的常数, 得到的结果就是大O阶
常见的复杂度
常数阶 => O(1)
线性阶 => O(n)
对数阶 => O(log2n,缩写为logn)
平方阶 => O(n2)