数据结构的逻辑结构和存储结构
逻辑结构:线性表(1对1)、树(1对多)、图(多对多)
存储结构:顺序存储和链式存储
线性表
顺序存储的线性表。时间复杂度:索引取值O(1);据值查找O(n);插入O(n);删除O(n)。
链式存储的线性表。有单链表、双向链表、循环链表。时间复杂度:索引取值O(n);据值查找O(n);插入O(1);删除O(1)。
栈
栈先进后出,push压栈,pop弹栈,支持顺序存储和链式存储,用两个指针维护栈的情况。时间复杂度:索引取值O(n);据值查找O(n);插入O(1);删除O(1)。
队列
队列先进先出,队尾增加元素,队头删除元素,支持顺序存储和链式存储,其中顺序存储为了防止假溢出的情况,一般采用循环队列。时间复杂度:索引取值O(n);据值查找O(n);插入O(1);删除O(1)。
字符串
一般采用顺序存储,一般整个串整体操作。
串的模式匹配
数组
广义表
树和二叉树
二叉树的性质
- 二叉树第i层最多有2i-1个结点。
- 深度为k的二叉树最多有2k-1个结点。
- 完全二叉树性质:入度为1的结点只能有1个或0个;入度为0的结点数=入度为2的结点数+1。
- 树的结点数=树的边数+1。
- M个结点有M*2个指针(对于二叉树是2*M,n叉树是n*M),有M-1条边。
- N个结点的二叉树有N+1个空链指针。
二叉树的存储结构
一般用链式存储,有二叉链表、三叉链表,对于满二叉树或完全二叉树也可以用顺序存储(层序遍历)。
遍历二叉树(算法掌握)
先序遍历、中序遍历、后序遍历、层序遍历。
掌握:
- 遍历算法的递归、非递归;
- 队列实现的层序遍历;
- 根据遍历序列确定二叉树,包括创建二叉链表
- 计算二叉树的深度、结点数、获取结点父结点
- 统计二叉树中结点个数
树的存储结构
有双亲表示、孩子表示和使用最多的孩子兄弟表示(左孩子右兄弟)。
森林和二叉树的转换
左孩子右兄弟的方法。
哈夫曼树(最优二叉树)
概念:根结点到所有叶子结点到带权路径最优的二叉树。
哈夫曼树构造:
- 在森林中找到两个权值最小的树,作为左右子树构造一个新的二叉树,二叉树的根权值为左右子树权值之和。
- 将森林中的原来的两个树删除,并加入新的树。
- 重复1,2,知道森林只有一棵树,那棵树就是哈夫曼树。
哈夫曼编码:核心是为出现次数多的字符编较短的码。
特殊二叉树
满二叉树
只有度为0和度为2的结点。
完全二叉树
除了最后一层,其他层的各个结点度都为2,最后一层的结点度为0或1。
哈夫曼树/最优二叉树
特点:1树的带权路径(根结点到所有叶子结点到路径长度和权的乘积之和)最小;2权重大的离根结点越近
二叉查找树/二叉排序树/二叉搜索树/BST
左子树都比根结点小,右子树都比根结点大
特点:和折半查找类似,从根结点开始查找,如果相等查找结束;如果查找的关键字大于根结点,根据二叉排序树的定义,再在右子树上查找;如果查找的关键字小于根结点,则在左子树上查找。链表实现。适合经常查询、增删。二叉排序树的查找效率跟树的形态有关,树的形态跟数据集有关,如果数据集有序排列,那么查找的时间复杂度是O(n),如果分布合理时间复杂度是O(log2n),树的高度越小查找越快。二叉树的删除还涉及合并结点,分裂结点的情况。
平衡二叉树/AVL
红黑树
图
图的存储结构
- 二维数组表示的领接矩阵+顶点的一维数组。适用于顶点多、边少的图。
查找
顺序查找、折半查找、分块查找、二叉排序树和平衡二叉树都是针对内存的查找算法,是内查找法。而B树和B+树是针对外存、大文件的查找,属于外查找法。
线性表的查找
顺序查找
算法说明:是指从表的一端开始依次和关键字进行比较,若相等则查找成功,若整个表都没有相等的值,则查找失败。
适用范围:适合线性表和链表。
实现方式:遍历整个表即可。也可以通过设置监视哨(令扫描的表的最后一个元素等于一个值)能提高效率。
时间复杂度:O(n)。
折半(二分)查找
算法说明:从表的中间元素开始查找,如果相等查找结束;如果查找的关键字大于或小于中间元素,则在大于或小于的区间再次这样递归查找。
适用范围:顺序表,且顺序表必须是有序排列的。适合表数据变化不大的。
实现方式:可以采用递归的方式。
时间复杂度:O(log2n)。
备注:其实现过程可以用二叉树表示,左子表和右子表分别为根的左子树和右子树,这种二叉树成为折半查找的判定树。折半查找的关键字判断次数最多不查过判定树的深度,也因此时间复杂度跟判定树的深度和n的关系。
分块(索引顺序)查找
算法说明:是顺序查找和折半查找的结合。除了无序的分块表之外还要维护一张有序的索引表,块中数据无序排序用顺序查找,索引表用折半查找。
适用范围:适合需要快速查找但又会频繁改动的线性表。
树的查找
二叉排序树
定义:左子树上的值都小于根结点的值,右子树上的值都大于根结点的值。(中序遍历递增,可以看作一个有序表,所以和折半查找类似)。
查找算法说明:和折半查找类似,从根结点开始查找,如果相等查找结束;如果查找的关键字大于根结点,根据二叉排序树的定义,再在右子树上查找;如果查找的关键字小于根结点,则在左子树上查找。
适用范围:链表实现。适合经常查询、增删。
备注:二叉排序树的查找效率跟树的形态有关,树的形态跟数据集有关,如果数据集有序排列,那么查找的时间复杂度是O(n),如果分布合理时间复杂度是O(log2n),树的高度越小查找越快。二叉树的删除还涉及合并结点,分裂结点的情况。
时间复杂度:插入:O(log2n);创建:O(nlog2n);删除:O(log2n);查找:O(log2n)。
平衡二叉树
定义:是一种特殊的二叉排序树,在二叉排序树的基础上还有一个特性,左子树和右子树的深度差绝对值不超过1。
查找算法说明:和二叉排序树一样。
适用范围:链表实现。适合经常查询、增删。
备注:二叉排序树能够做到类似折半查找的性能要求,又能克服折半查找不适合动态数据的特性,但是二叉排序树的查找性能受数据集的影响很大,因此才有了平衡二叉树。
平衡二叉树的平衡调整:
时间复杂度:插入:O(log2n);创建:O(nlog2n);删除:O(log2n);查找:O(log2n)。
B树
定义:是一个平衡多叉树
B+树
散列表的查找
排序
插入排序(插入排序是指将一个新数据插入到一个有序数据集中)
直接插入排序
算法思想:对于一个要排序的数组,将数组的第一个元素看成一个子序列,从数组的第二个元素开始在子序列中顺序查找并比较大小,以从小到大排序为例,那么原数组中的元素若比有序的子序列小,那么接着查找;如果比有序的子序列大,大的位置就是要插入的元素的位置;如果查找结束了,那么第0个索引就是要插入的元素的位置,然后将插入位置之后的元素都后移,以这种方式从第二个元素开始直到原数组最后一个。
时间复杂度:O(n2)。
空间复杂度:O(1)。
算法特点:算法稳定简单,可用于顺序、链式结构,适合初始基本有序的序列。
折半排序
算法思想:类似于直接插入排序,只是在查找的时候使用的是折半查找的方式。
时间复杂度:O(n2)。
空间复杂度:O(1)。
算法特点:算法稳定;因为要使用折半查找所以只能使用顺序存储;适合初始记录无序,n较大的情况。
希尔排序
算法思想:希尔排序也称为缩小增量排序。传统的直接插入排序在序列基本有序,插入数据较少时性能较好,但是如果将一个逆序的序列变成正序的话,效率很差。针对此,希尔排序采用缩小增量的方式进行排序,有一个增量序列,然后在要排序的序列中,分组跳跃进行排序,最后一趟的增量是1,在这一趟的时候序列已经基本有序。
时间复杂度:跟增量序列的选择有关,希尔增量(二分数组长度)是O(n2),理论最低值是O(log2n)2。
空间复杂度:O(1)。
算法特点:算法不稳定;只能用于顺序存储,适合初始无序,插入元素多的情况。
交换排序
冒泡排序
算法思想:通过将相邻元素两两对比,如果逆序就交换位置。
时间复杂度:O(n2)。
空间复杂度:O(1)。
算法特点:算法稳定;可用于链式存储和顺序存储;性能比直接插入排序差。
快速排序
算法思想:关键就是去一个基准点,然后每一趟让基准点到该去的位置。假如排序是从小到大,取基准点是第一个元素,然后建立两个哨兵,一个哨兵从右往左探测,当哨兵处的值小于基准值,哨兵停下来,然后另一个哨兵从左往右探测,当哨兵处的值大于基准值,哨兵停下来,然后交换两个哨兵位置的值,再接着同样的两个哨兵继续探测,当两个哨兵的位置重合,将重合点和基准点交换,这样就完成了一趟,然后依次递归左子表和右子表,直到拆不出子序列。
时间复杂度:平均O(nlog2n),最坏O(n2),最好O(n)。
空间复杂度:最好O(log2n),最坏O(n)。
算法特点:算法不稳定;只能用于顺序存储;速度最快,适合n大,初始无序。
选择排序
简单选择排序
算法思想:假定带排序序列的第一个元素有序,然后从第二个到最后一个顺序查找出一个最小的,然后将这个元素和第一个元素交换,然后依次重复n-1次。
时间复杂度: O(n2)。
空间复杂度: O(1)。
算法特点:算法稳定;用于顺序存储、链式存储。
堆排序
算法思想:是一个树形选择排序(简单选择排序的改进)。排序主要分为3步:1.将无序序列构造成一个堆结构,然后根据升序还是降序选择大根堆还是小根堆(升序大根堆,降序小根堆);2.将堆顶元素和最后一个元素交换,然后重新调整堆,使得满足堆结构;3.重复执行交换、调整。
时间复杂度: 总的时间复杂度O(nlog2n),主要分为两部分,第一部分初建堆O(n),第二部分调整堆O(log2n)。
空间复杂度: O(1)。
算法特点:算法不稳定;只能用于顺序存储。
备注:这里设计堆堆数据结构定义:堆是一个完全二叉树,并且每个结点的值小于(大于)等于其左右结点的值,小根堆(大根堆)。
归并排序
算法思想:最简单常用的是2路归并。这里的意思就是将两个有序的序列合并成一个有序的序列。例如一个初始长度n的无序序列,可以看出n个有序的长度为1的有序序列,然后将相邻的两子序列通过归并,这样一趟归并之后有n/2个有序的子序列,重复步骤,最终整个序列有序。特别需要注意的是,归并的实现方式:每次从两个有序子序列中个取一个元素进行对比,将较小者(假设是升序)放入记录表,直到某个表为空,然后就另一个表都放入记录表即可。
时间复杂度: O(nlog2n)。
空间复杂度: O(n)。
算法特点:算法稳定;用于顺序存储、链式存储。
基数排序
算法思想:将带排序统一成同一位数,然后从低位开始,依次进行排序。