[408] NOTES on DataStructure -计算机考研408笔记-数据结构

[408] NOTES on DataStructure

1 绪论

  1. 快慢指针
Type foo(Node *head) {
	Node *slow, *fast;
	slow = fast = head;
	while (fast->next) {
		slow = slow->next;
		fast = fast->next;
		if (fast->next) fast = fast->next;
	}
	...
}

2 线性表

  1. 顺序表

    1. 插入元素平均移动次数:sum p(n-i+1) = n/2
    2. i位置插入元素,后移的元素个数:n-i+1
    3. 删除元素平均移动次数:sum p(n-i) = (n-1)/2
    4. i位置删除元素,前移的元素个数:n-i
    5. 顺序查找比较次数:sum p*i = (n+1)/2
  2. 链表

    1. 头插法:生成的链表结点次序与输入数据的顺序相反,可用于逆置链表
    2. 循环单链表判空:头指针的指针指向自身
    3. 静态链表:借助数组实现,next==-1标识链表结束
  3. 常见考法

    1. 将两个有n个元素的有序表归并的最少比较次数、最多比较次数?
      1. 最少:固定一张表不改变,另一张表移动完:n-1
      2. 最多:交替移动,2n-1

3 栈和队列、压缩存储

  1. 栈:

    1. n个元素入栈,出栈元素的排列个数:卡特兰数(C(n, 2n) / (1+n))
    2. 应用:
      1. 括号匹配
      2. 表达式求值
      3. 求解二叉树不同形状个数
        1. 一定的先序+中序遍历可确定一棵二叉树
        2. 先序:根左右,看作入栈顺序
        3. 中序:左根右,看作出栈顺序
        4. 给定N个元素的先序,相当于给定入栈顺序,出栈顺序为卡塔兰数
        5. 卡塔兰数:C(N, 2N) / (N+1)
  2. 队列:

    1. 链队
      1. 出队操作:可能头、尾指针都要修改(出队到空,尾指针指向NULL)
      2. 队空:front == NULL,rear == NULL
      3. 非空情况:rear指向链尾
    2. 循环队列:牺牲一个位置用于判断是队空还是队满
      1. 队空:front == rear
      2. 队满:(rear+1) % N == front
      3. 元素个数:(rear - front + N) % N
    3. 双端队列
      1. 队列输出顺序:1234为双端队列输入
        1. 输入受限、不能输出受限:4132
        2. 不能输入受限、输出受限:4213
        3. 不能输入受限、不能输出受限:4231
  3. 对称矩阵:只存放主对角线和下三角区的元素
    即各行存放个数:1+2+3+…+n = n(n+1)/2

  4. 三角矩阵:只存放主对角线和上/下三角区的元素以及另一三角区的常量
    即各行存放个数:1+2+3+…+n+1(常量) = n(n+1)/2 + 1

  5. 三对角矩阵:非零系数在三条对角线上(主对角线、高、低对角线)

4 树与二叉树

  1. 二叉树

    1. 二叉树与度为2的树:
      1. 度为2的树至少有3个结点、二叉树可以为空或只有1个孩子
      2. 二叉树无论孩子个数都有左右之分
    2. 满二叉树
      1. 高度为h,结点数为2^h-1个的二叉树
      2. 若二叉树采用顺序存储,则要按照满二叉树的结点数分配存储空间
    3. 完全二叉树
      1. 每个结点都与相同高度的满二叉树编号一一对应的二叉树
      2. 叶子结点可以出现在最后一层以及倒数第二层
      3. 度为1的结点至多1个,而且只有左孩子
    4. 二叉排序树 BST:中序序列为有序序列
      1. 删除结点
        1. 叶结点直接删除
        2. 只有一棵子树,让该子树代替被删除结点
        3. 有两棵子树,让其中序第一个子女替换,转换为删除那个结点
      2. 查找效率:O(logN)
    5. 霍夫曼树:带权路径最短的二叉树
      1. 带权路径:各个叶子结点(高度*权值)之和
      2. 对N个结点编码
        1. 新建了N-1个结点
        2. 共2N-1个结点
      3. 不存在度为1的结点
      4. 沿着霍夫曼树的边得到的是前缀编码
      5. 扩展到N叉树情况:补虚拟“0“叶子结点,补齐N整数倍个结点
    6. 平衡二叉树:由二叉排序树发展而来
      不平衡情况调整:
      1. 单旋转:LL旋转、RR旋转
      2. 双旋转:LR旋转、RL旋转
        注意被调至根处的结点原先子树相对左右位置不变
    7. 线索二叉树
      按某一遍历顺序的到序列,对每一结点:
      1. 无左子树,左指针指向前驱结点
      2. 无右子树,右指针指向后继结点
      3. 无前驱或后继则指向NULL
  2. 二叉树遍历与树

    1. 二叉树遍历:确定唯一的二叉树
      1. 先序和中序
      2. 后序和中序
      3. 层次遍历和中序
      4. 层次遍历和后序
      5. 先序与后序不能确定唯一的树,但能确定结点之间的祖先关系:
        对两个结点X、Y,若先序中相对顺序为XY,后序中为YX,则X是Y祖先
    2. 树的后根遍历对应森林的中序(也有称后序)遍历、二叉树的中序遍历
    3. 树转换为二叉树
      1. 每个结点左指针指向第一个孩子,右结点指向右兄弟
      2. 图示即,兄弟之间连线,每个结点只保留和第一个孩子的连线
    4. 森林转换为二叉树
      1. 先把每棵树转换为二叉树
      2. 每棵树根结点视为兄弟关系,以第一棵树根结点为根
    5. 二叉树转换为森林
      1. 断开根结点与右子树连接,得到两棵二叉树
      2. 第一棵为原森林第一棵树,接下来递归进行第一步
  3. 常用结论

    1. 树的度是结点数减1
    2. n个结点的二叉链表有n+1个空链域
    3. n个结点的二叉线索树有n+1个线索数
    4. 非空二叉树叶子结点数为双分支(度为2)结点数加1
    5. n个结点能构成的二叉树种类:卡特兰数 C(n, 2n)/(1+n)
    6. 先序和后序遍历正好相反的二叉树一定是高度等于结点数的二叉树
    7. 叶子结点的先后顺序在各个遍历方式中都一样
    8. 叶子结点不一定在最底层
    9. 高度为h的平衡二叉树最少的结点数有规律,记为Nh:
      1. N0 = 0,N1 = 1
      2. Nh = Nh-1+Nh-2+1
      3. 相同表述:非叶结点平衡因子均为1
    10. 每个非叶子结点平衡因子均为0的平衡二叉树一定是满二叉树
    11. 二叉排序树插入时候没有平衡操作,发展成平衡二叉树才进行平衡
    12. 中序有序的AVL树注意区分中序是降序还是升序
      1. 降序:树中最大元素一定没有左子树
      2. 升序:树中最小元素一定没有左子树
    13. 二叉排序树、平衡二叉树,删除结点x后再插入x
      1. 二叉排序树
        1. x为叶子结点,树结构不变
        2. x为非叶子结点,树结构改变
      2. 平衡二叉树:无论x是不是叶结点,都可能改变或不变

5 图

  1. 简单图、路径、回路

    1. 简单图:不存在重复边或顶点到自身的边
    2. 简单路径:顶点不重复出现的路径
    3. 简单回路:除第一个顶点和最后一个顶点,其他顶点无回路
  2. 强连通图

    1. 有向图概念
    2. 每对顶点之间都有到对方的路径
    3. 强连通分量:极大强连通子图,再添加顶点就不连通
  3. 生成树

    1. 包含全部顶点的极小连通子图,再添加边就出现环路
    2. 顶点数为n的图,生成树有n-1条边
    3. 由此,顶点数为n的图,有大于n-1条边则一定有环
  4. 带权图:边带权值,也称为“网”

  5. 稠密图、稀疏图:边很少的图称为稀疏图,衡量标准:|E|< |V|log|V|

  6. 存储方法

    1. 邻接矩阵
      1. 容易确定两个顶点是否有边
      2. 确定边数需要逐个位置检测
      3. 适合稠密图存储
      4. 表示唯一
      5. 拓展:若记到自己的边以及无法到达的边值为0,矩阵A
        1. A^m = B,B中有非0元素Bij = k,k ≠ 0
        2. 非0元素含义:从i到j长度为m的路径有k条
    2. 邻接表
      1. 容易确定任意顶点的所有邻边
      2. 方便计算有向图顶点出度
      3. 计算有向图顶点入度需要遍历检测
      4. 表示不唯一
    3. 十字链表:用于有向图
    4. 邻接多重表:用于无向图
  7. 图遍历

    1. BFS
      1. 时间复杂度
        1. 邻接表:O(V + E)
        2. 邻接矩阵:O(V^2)
      2. 可用于最短路径问题
      3. 类似于二叉树的层次遍历
    2. DFS
      1. 时间复杂度
        1. 邻接表:O(V + E)
        2. 邻接矩阵:O(V^2)
      2. 连通图DFS经过的边形成一棵生成树
      3. 类似于二叉树的先序遍历
    3. 连通性
      1. 无向图:一次遍历访问到全部结点则连通
      2. 有向图:从初始点能访问到所有结点则连通
  8. 最小生成树:权值之和最小的生成树

    1. 不一定唯一、但权值之和为一
    2. Prim算法:距离已有树最近顶点加入生成树
      1. 时间复杂度:O(V^2)
      2. 适合求解稠密图的情况
    3. Kruskal算法:选择未选的、权值最小的、连接不同分量的边加入生成树
      1. 判断是否连接不同分量:并查集
      2. 时间复杂度:O(log E)
      3. 适合求解稀疏图的情况
    4. 最小生成树唯一的条件
      1. 所有权值均不相等
      2. 有相等权值的边,但在构造时权值相等的边都被加入最小生成树
  9. 最短路径

    1. Dijkstra:单源最短路径
      1. 辅助数组:
        1. dist:记录源点到各个顶点当前最短路径长度,无路径为无穷大
        2. path:从源点到各个顶点最短路径的前驱结点
      2. 流程:
        1. 初始化
        2. 选取当前dist中值最小、未访问的顶点
        3. 根据选取的结点更新dist、path
        4. 重复n-1次2~3步
      3. 时间复杂度:O(V^2)
    2. Floyd:各顶点之间最短路径
      1. 流程:
        1. 初始化:邻接矩阵中,有边则对应位置值为边权值
        2. 逐步尝试加入顶点,若使得路径长度减小则更新
      2. 时间复杂度:O(V^3)
      3. 适用于带权无向图
  10. 关键路径

    1. 关键路径:源点到汇点的最大路径长度的路径
    2. 关键活动:关键路径上的顶点(活动)
    3. 计算步骤
      1. 计算ve
        1. 源点ve=0
        2. 其他结点取最晚(max)的到达时间
      2. 计算vl
        1. 汇点vl=ve
        2. 其他结点取最早(min)的发生时间
      3. 计算e:e = 该活动(边)起点的ve
      4. 计算l:l = 该活动(边)终点的vl-活动时间(边权)
      5. 找到l与e相等的顶点
    4. 不能任意缩短关键活动,因为缩短到一定程度可能不再是关键活动
    5. 可能存在多条关键路径,加快同时在所有关键路径上的活动才能缩短时间
  11. 常见问题

    1. N个顶点无向图,任何情况都连通(边怎么变化都连通):(N-1)*(N-2)/2+1
      只需去除一个结点后保证是完全连通子图,再添加一条边将剩下结点连接上
    2. 有向图邻接表存储,删除一个结点时间复杂度:O(V + E)
      1. 删除出边只需要删除该结点的邻接表项
      2. 删除入边需要遍历所有边
    3. 生成树与连通子图、连通分量
      1. 极大连通子图 = 连通分量
        1. 连通无向图中:即该图本身
        2. 不联通无向图中:各个连通分量
      2. 极小连通子图 = 生成树

6 查找

  1. 平均查找长度:衡量查找算法效率最主要的指标

    1. 查找长度:需要比较的关键字次数
    2. 平均查找长度 ASL = sum p*c
  2. 顺序查找

    1. 成功ASL = sum pi * (n-i+1) = (n+1)/2
    2. 失败ASL = n
    3. 有序表失败ASL = n/2 + n / (n+1)
  3. 折半查找

    1. 成功ASL = log2(n+1) - 1
    2. 通过判定树进行分析
      1. 计算每个关键字查找成功的长度
      2. 计算查找长度总和
      3. 成功平均ASL = 长度总和 / 关键字数
    3. 判定树的特征与合法性
      1. 判定树是一棵平衡二叉排序树,中序序列有序
      2. 折半查找过程必须统一使用向上取整或向下取整
      3. 同时出现两种取整方法都的二叉排序树不是合法判定树
      4. 判断时,由上至下递归进行判断
      5. 参考:折半查找判定树
  4. B树

    1. m阶B树:所有结点孩子个数最大值为m,m叉平衡查找树
      1. 至多有m棵子树,m-1个关键字
      2. 根结点若非终端结点,则至少有2棵子树
      3. 所有非叶结点至少有m/2棵子树(向上取整),至少有m/2-1个关键字
      4. 叶子结点在同一层次,都不带有信息
      5. 结点关键字数 = 结点孩子数 - 1
    2. m阶B+树:
      1. 结点的索引项只含有对应子树的最大关键字,不存储记录
      2. 结点关键字数 = 结点孩子数 - 1
      3. 叶结点包含全部关键字
      4. 存在一个指针,指向值最小的叶子节点,所有叶子连接成一个链表
    3. 高度为2的m阶B树,最少的关键字个数:m个
      根结点达到m-1个关键字时,再加入一个关键字就分裂出第二层。
  5. 散列表

    1. 装填因子:关键字个数 / 表长;装填因子越大,ASL越大
    2. 冲突处理:
      1. 开放定址法
        1. 线性探测:容易出现聚集,冲突后向“前”查找空闲单元
        2. 二次探测:逐次尝试±i^2
      2. 拉链法:冲突记录存储在一个链表中,不出现聚集现象
    3. 计算ASL:如H = key mod m
      1. 列出存储结构(表)
      2. 查找成功:根据key来查
        1. 列出每个key的比较次数
        2. ASL = (比较次数和) / key个数
      3. 查找不成功:根据地址0~m-1来查
        1. 列出每个地址0~m-1查找到空的比较次数(包含与空位置比较)
        2. ASL = (比较次数和) / 地址个数m
    4. 提高散列表查询效率
      1. 减小装填因子
      2. 设计冲突少的散列函数
      3. 处理冲突时避免产生聚集现象
    5. 若使用开放定址法,不能直接删除元素,只能标记为删除状态,否则会导致搜索路径被中断。

7 排序

  1. 稳定排序

    1. 直接插入排序
    2. 折半插入排序
    3. 冒泡排序
    4. 归并排序
    5. 基数排序
  2. 不稳定排序(快“些”选一堆,“些”谐音“希”)

    1. 希尔排序
    2. 快速排序
    3. 简单选择排序
    4. 堆排序
  3. 外部排序:归并排序
    最佳归并树:霍夫曼树思想
    分析:两个有序表的合并最坏情况比较次数是m+n-1,依赖于表长,利用霍夫曼树最短带权路径的特性,能最小化比较次数。

  4. 复杂度分析

    1. 时间复杂度
      1. O(n^2)
        1. 直接插入排序
        2. 折半插入排序
        3. 冒泡排序
        4. 选择排序
      2. O(nlogn)(快“些”归“队”,“些”谐音“希”,“队”谐音“堆”)
        1. 快速排序
        2. 希尔排序
        3. 归并排序
        4. 堆排序
      3. O(d(n+r)):基数排序(如930,d位数=3,r基数=10)
    2. 空间复杂度
      1. 快速排序:O(logn)
      2. 归并排序:O(n)
      3. 基数排序:O®
      4. 其他:O(1)
  5. 堆排序

    1. 时间复杂度:O(nlogn)
    2. 空间复杂度:O(1)
    3. 确定大量数据中前少数部分序列
    4. 建堆调整:自右向左,自下而上进行检测,发生调换时后递归进行下去直到被调换结点满足堆的条件
    5. 删除结点:将最下层、最右边一个结点填补删去的位置,再调整
  6. 排序原理与常见问题

    1. 每一趟排序确保一个关键字到达最终位置
      1. 交换类(冒泡、快速)
      2. 选择类(选择、堆)
    2. 关键字比较次数与原始序列无关:选择排序、折半插入排序
    3. 排序趟数与原始序列有关:交换类
    4. 元素移动次数与原始序列无关:基数排序(无论如何都进行收集)
    5. 已经递增原始序列排序:直接插入最省时,快速排序最费时(达到最坏)
    6. 确定大量数据中前少数部分序列:堆排序
    7. 顺序存储更换为链式存储,希尔排序、堆排序效率降低,这两个排序算法利用了顺序存储的随机访问特性
    8. 第n趟快速排序后,定有n个元素,左边元素都小于它,右边元素都大与它
    9. 快速排序的递归次数与初始序列有关,与划分后分区的处理顺序无关
    10. 希尔排序组内采用直接插入排序
    11. 升序链表归并为降序链表:头插法,复杂度O(max(m, n))
    12. 注意外部排序最佳归并树是霍夫曼树,m路归并,补虚拟“0“叶子结点,补齐最底层有m个叶子结点。

to be continue
Karl 2020/12/24

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值