1.绪论
数据元素:数据的基本单位
数据项:数据的不可分割的最小单位
数据结构:(D,S),数据元素的有限集和其上关系的有限集
抽象数据类型:(D,S,P)数据对象、关系集、基本操作集
算法特性:有穷确定可行输入输出
2.线性表
线性结构特点:存在唯一上下界,除上下界外均存在前后驱
顺序存储
优点:①存储紧凑②可随机访问
缺点:①插入、删除操作移动大量元素②预分配空间利用不充分③表容量难以扩充
链表
优点:①便于插入、删除②对空间的利用较为充分
缺点:①不能随机存取②指针域占用空间③查找较慢
3.栈和队列
栈:FILO,队列:LIFO
循环队列:(解决真假溢出问题)让sq[0]接在sq[len-1]之后,若判断位rear+1=M,则rear=0;
4.串
使用“堆分配”实现串数据结构
5.数组和广义表
按行切分:{{00,01,...0n}{10,11,...,1n}...}按行从左往右从上往下依次存储
按列切分:按列从上往下,从左往右依次存储
稀疏矩阵:三元组列表
十字链表:{i,j,e,down,right}存储,
广义表的表头:第一个元素(可能是原子也可能是广义表)位表头(Head),!!其余元素组成的表!!是表尾(Tail)
6.树与二叉树
树的度:各结点度的最大值
完全二叉树:从上到下从左到右依次编号可以连贯。满二叉树编号从尾部开始删除。
特点:叶子节点旨在层次最大的两层上出现,k-1层都是满的,k层全部在左边
五个性质:
1.第i层至多有2^(i-1)结点
2.深度为k的二叉树至多有2^(k)-1结点
3.终端节点(叶子)数为n0,度为2的结点数为n2,n0=n2+1
4.具有n各结点的完全二叉树的深度为 取⌊logn⌋+1
5.完全二叉树的结点按层序编号,i=1为根节点,2i>n时无左孩子,否则2i为左孩子。2i+1>n无右孩子,否则2i+1为右孩子
三种遍历:依照根节点访问次序:DLR,LDR,LRD为先中后,LR位置不变。
遍历二叉树的非递归描述:(基本不考)
线索二叉树:使用LRtag区别子树和前后,头节点lc指向根节点,rc为后继,指向最后一个结点
关键:①注意线索的“序”②前驱/后继/全线索化③空指针处才能增加线索
树的存储结构:
双亲结构:(d,p)找双亲容易找孩子难
孩子表示:(c,next_c)找孩子容易找双亲难
上述两种综合:(d,p,c,nc)都好找但是增加空间
孩子兄弟:(d,p,s)左孩子右兄弟,优点便于操作,缺点破坏层次
-->任意树转换为二叉树:①兄弟连线②除左孩子外全部抹线③旋转整理
-->树还原二叉树:还原上述操作即可
树的先后根遍历:DL1L2...R2R1(先根)L1L2...R2R1D(后根)
哈夫曼树:
树的路径长度:从树根到每一个结点的路径个数(路径长度)之和
带权路径长度:WPL=Σwl,w为某指定结点的权
哈夫曼树构造算法:原则:一直选取集合里两个元素进行加和使和最小,生成结点插入到原序列里
哈夫曼编码:字频为权,左0右1,任何一个字符的编码不能是另一个字符编码的前缀
7.图
生成树:极小连通子图,n顶点和n-1边
十字链表:v=(d,ie,oe),e=(tail,head,hl,tl,info),hl,tl是弧头/尾相同的下一条弧指针,ie,oe为指向该结点的入/出弧
生成树:BFS/DFS经过的点、边画出来的树成为广度/深度优先生成树
最小生成树:
Kruskal:依次选取权最小的边生成无环图(适合边稀疏)
Prim:(加点)依次选取点,往里面添加点。(适合边稠密)
拓扑排序:①选择任意入度为0的顶点开始②删除该顶点及其关联弧③继续12
一个AOV网的拓扑排序不唯一
关键路径:最长路径
ve从最后开始推,vl从最前端开始推。因此要先推出vl
el是边,和vevl同理
Dijkstra算法(?)
9.查找
平均查找长度ASL:Σpc,c为比较次数,p为查找概率
静态查找
顺序表:成功ASL=(n+1)/2,失败为n+1
折半查找:成功ASL=log_2(n+1)-1。
索引顺序表:对顺序表分块存储。成功ASL=La+Lw,La为在索引项中查找的ASL,Lw为在对应的块中的ASL
动态查找:查找不成功时插入
二叉排序树:左小右大(中序遍历是有序序列),最差深度n,最好深度 ⌊logn⌋+1
平衡二叉树:平衡因子:左子树深度-右子树深度,其绝对值差不大于1
构造平衡二叉树
调整:
LL(R):中为支点,高度结点进行顺时针旋转(R)
RR(L):中为支点,高L
LR(LR):将下面的整体先左转。然后转换为LL型
RL(RL):将下面的整体先右转,转换为RR型
旋转产生第三结点时进行重新插入
B+/B-树:数据元素多,例如磁盘
阶:结点中最大的孩子数
非终端结点至少有两棵子树
除根节点外的所有非叶子结点至少有 ⌈m/2⌉棵子树,关键字:⌈m/2⌉-1
关键字至少 ⌈m/2⌉-1 最多m-1
叶子结点不含信息,在同一层。
哈希法:
哈希函数的创建方法:
直接定址(关键字的线性函数)
数字分析(设法令分布均匀)
平方取中(取平方的若干位)
折叠(将数字按几位分为一组加和)
除留余数(H=key mod p,p为不大于表长的素数或者不小于20的质因数的合数)
伪随机数法
处理哈希函数冲突:
开放定址法(由多值函数生成一个探查序列(具体是在H(key)后面线性/平方/随机生成一个加和序列),然后依次查找空位)
链地址法(空位链表)
再哈希法(用备用哈希函数)
建立公共溢出区
哈希法分析:
效率高
表越满(装填因子越接近1),冲突可能性越大,查找越慢
ASL不定(由于处理冲突的函数不同)
线性探测再散列容易导致二次聚集(二次冲突)
开放定址:表长必须大于记录数
10.排序
插入
->直接插入
整个排序过程为n-1趟插入,即先将序列中第1个记录看成是一个有序子序列,然后从第2个记录开始,逐个进行插入,直至整个序列有序。
->折半
->2路插入(估计不考)
创建一个循环串,将第一个元素视为定序的中位,然后在其前后插入
->希尔(不稳定排序)
分别取间隔不同的组进行多次插入排序,最后整体插入排序
增量序列为2^(t-k+1) (式中t为长度,k为0~n-1)时其复杂度为n^(3/2)
增量序列取法:①没有除1以外的公因子②最后增量必须为1
交换
->冒泡
12比较交换,23比较交换...以此类推成为一趟排序
第一趟排序以后进行第二趟1~n-1,类推
时间复杂度(比较,移动):(n-1,0),(0.5(n²-n),1.5(n²-n))
->快速
取r[s]为枢纽关键字,在头部和尾部放置指针。头部指针内容与r[s]比较,往后找如果比r[s]小则替换r[s],尾部指针往前找,大则替换,直至两指针重合。然后分别进行快排。
时间复杂度:最好nlogn,最坏n²,空间复杂度:最好n最坏logn
选择
->简单选择(不稳定)
一直找最小的,从前先后找,最小的排在前面不再查询。
时间复杂度:最好0,最坏3(n-1),比较次数0.5(n²-n)
->堆(不稳定)
小顶堆:k[i]<=k[2i] && k[i]<=k[2i+1](即其对应的奇偶下标元素)
大顶堆与小顶堆相反。
堆的筛选:①输出堆顶元素,用最后元素替代。②根节点与左右子树根节点比较,交换较小值③重复1,2直至叶子节点。
生成堆(调整):①从⌊n/2⌋元素开始到第一个元素反复筛选(与左右子树比较,交换较小值)
时间复杂度:最坏nlogn.筛选:最多从1到最底层,完全二叉树深度为 ⌊logn⌋+1,初始建堆:调用筛选算法 ⌊n/2⌋次,重建堆:调用n-1次
归并
->2路归并
一直两两归并,合并生成有序段之后再合并有序段。
时间复杂度:nlogn,每次两两归并调用merge ⌈n/2h⌉次,h为有序段长度,整个归并进行⌈logn⌉次
基数
使用队列依次收集个位、十位、百位等数据,先进先出,依次存放入各个队列。
总结:
1.时间性能:
->nlogn : 快排、堆排序、归并排序。快排最快,n较大时归并更快
->n² : 插入、冒泡、选择。插入排序对基本有序序列有效。选择排序移动较少
->n : 基数。对n值很大,关键字较小的序列
----关键字顺序有序时,冒泡、插入时间复杂度On,快排最慢,为n²
----选择、堆、归并不随记录序列中关键字的分布而改变
----冒泡涉及到移动记录,因此效率最低。
2.空间性能:
->1 : 插入、冒泡、选择、堆排序的辅助空间(简单排序方法都是1)
->logn : 快排:递归程序中栈辅助空间
->n : 基数、归并
3.稳定性能(关键字相等的记录在排序前后位置不变)
不稳定:希尔、快排、简单、堆
4.选择建议:
-1 n较小:插入。数据项较大:选择
-2 n较大:快排。如果序列趋向有序,则应该考虑堆、归并
-3 n较小时快排、归并性能不及直接插入,应该与插入混合使用