时间复杂度&空间复杂度
- 时间复杂度
考虑方面:
1. 循环语句执行次数与规模n的函数关系式
2. 递归 - 空间复杂度
考虑方面:
1. 开辟额外空间与规模n的函数关系式
2. 递归深度
代码题要点
typedef struct xxx(随便起){
xxxxx
struct 随便起的名字 * next;
}自己需要的名字;
- 所有指针变量一行一行写。
- 如果有结构体注意有没有XXXXX.xxxx进行访问内容。
- 只有指针才能用 -> 表示直接访问数据内容。
线性表
- 栈
- 不同元素出栈所有排列组合有1/n+1*C(n,2n)种
二叉树
- 线索化二叉树:利用二叉树叶子结点的空链域,连接先中后序序列的前驱后继结点,如果没有的话依旧指向空。
图
- 简单路径:路径上没有一个结点是重复的
- 简单回路:只有开头结尾结点重复,其余结点都不重复。简单回路不是简单路径。
- 距离,路径上面所有权重相加
- 连通图:仅谈无向图,任意两个顶点之间存在一条路径
- 连通分量:即极大连通子图
- 强联通图:仅谈有向图,任意两个结点互相之间都存在路径
- 无向图,如果是连通图至少(大于等于)有N-1条边
- 有向图,如果是强连通,至少(大于等于)需要N条边
- 四大存储结构:邻接矩阵、邻接表、十字链表(有向图)、邻接多重表(无向图)
查找
- 顺序查找O(N)
- 折半查找O(logn),最坏查找情况,即判定书树高log(n+1)向上取整
- 分块查找,采用顺序+顺序情况下,在块内存储根号(n)下,平均查找长度取最小值(根号(n)+1)
- 失败查找的平均查找长度看区间,以区间为单位计算(适用于所有查找)
二叉排序树
- 二叉排序树:插入,查找失败结点直接插入。破坏平衡,不向上传导,仅需找到第一个不平衡子树即可。
- 二叉排序树:删除,具体删除看章节。破坏平衡会向上传导,要一直迭代处理平衡直到根节点。
- LL:右单旋,RR:左单旋,LR:先左再右,RL:先右再左。口诀:相同取反做一次,不同按顺序做两次。
红黑树
- 红黑树叶子结点通常指的是空链域
- 红黑树四大条件:左根右,根叶黑,不红红,黑路同
B+/B-树
- B树关键字与子树个数差1
- B树除了根结点,其余结点关键字必须m/2向上取整-1个,子树必须m/2向上取整。m为阶数,即为m叉树
- 二叉排序树与B树删除非叶子(终端)结点都采用假删除,用前驱或者后继替换该结点,真正需要删除的是替代的前驱与后继所在的结点。
- B树删除后不满足定义下两种情况:1.找兄弟借一下 2.兄弟不够借,父结点下移,两个兄弟合并。有可能向上传导,需要迭代。
- B+树叶子结点包含所有关键字,B树关键字不重复
- B树关键字与子树个树差1,但是B+树相同
- B+树查找一定要找到叶子结点,而B树可能找到某一层就找到了
- B+树每一个结点都只是提供索引信息,并不包含真实数据,只有在叶子结点才存在指向真实数据的指针
- B+树叶子结点有指向前后叶子的指针,支持顺序查找
散列映射
- 装填因子为表中记录数/表长,拉链法中拉出来的链不算,所以装填因子可能大于1
- 注意题目的映射范围,映射不到的地方不需要纳入失败的考虑范围之内
- 装填因子与查找效率有关,装填因子越大,冲突概率越大
排序
所有的排序思想
- 插入排序:选一个数,插入到已经排序好的序列中,重复选第i,插入前i-1有序序列
- 折半插入排序:二叉搜索优化插入排序线性寻找插入位置
- 希尔排序:控制gap每次/2,保证每次总序列以gap为间隔的子序列都是有序的,当gap=1时即为插入排序,但此时已经总体有序。
- 冒泡排序:你懂得。所有排序最拉的一个。
- 快速排序:选取一个数,在序列中选取一个位置,保证左边的数全部小于这个数,右边的数大于这个数。然后左右两边递归上述操作。代码要背。
- 简单选择排序:每次选取最大/最小的丢在最后/最前。
- 堆排序:大堆顶/小堆顶。每一次将堆顶元素与堆低元素对调,视堆顶元素不在堆中了,进行维护堆操作(详见堆排序)。重复循环。
- 归并排序:一次归并:双指针,选定小的/大的纳入辅助数组,指针右移,直到两个数组都纳入辅助数组,最后辅助数组写会原数组。序列先两个两个一组,一组两个,执行一趟归并,然后两个两个一组,一组四个,一趟归并。。。。直到序列有序
- 基数排序:按位排序。以位出现的n中可能性开辟n个队列。一趟:遍历目前序列,以目前位(例如先个位)作为参考,纳入对应的队列。然后从位高到位低/从低到高,将每个对应的队列里面的元素按顺序出队。得到目前位的从高到低/从低到高顺序序列。然后换下一个位作为参考(例如十位),在进行一趟排序。。。。。直到每一位都排完
- 外部排序:实际即归并排序思想。内存开辟三个空间:输出缓冲区,输入缓冲区1,2.先读入两个块到输入缓冲区1,2。然后一次归并到输出缓冲区,满了写内存。然后在归并一次到输出缓冲区,满了写内存。然后再去外存调两块。。。执行几次直到每一个外存块都执行过了。这就保证了外存每两个块为一组内部都是有序的。然后将两个块为一组,按顺序从不同组掉两块进内存(调的两块组内也按顺序),归并。。。
排序细节点(注意交换以及比较)
- 堆排序如果右左右孩子,要先比较孩子选出最大/小,然后再与根节点比较。
- 堆排序中间不是交换,而是直接赋值,可以理解为n个数循环向前移一格。