数据结构
文章目录
- 数据结构
- 绪论
- 线性表
- 栈和队列
- 串
- 递归
- 数组
- 树和二叉树
- 图
- 查找
- 内排序
绪论
- 基本概念
- 数据:描述客观事物的bits
- 数据元素:表中的一条记录
- 数据项:表头
- 数据对象:表
- 数据结构:表的具体实现
- 数据结构的概念
- 逻辑结构
- 集合
- 线性
- 非线性
- 树
- 图
- 物理结构
- 顺序存储
- 链式存储
- 索引存储
- 哈希存储
- 数据运算
- 运算描述
- 运算实现
- 数据类型与抽象数据类型
- 算法:
- 算法特性:有穷,确定,可行,输入,输出
- 算法度量:
- 时间复杂度:渐进时间复杂度,随着问题规模n的增大,算法执行时间的增长率
- 空间复杂度:算法执行过程中零食占用存储空间大小的度量
- 数据结构+算法=程序
线性表
- 逻辑结构
- 逻辑特征:每个元素唯一前驱后继
- 存储结构
- 顺序表
- 基本特征:随机存取
- 链表
- 单链表
- 双链表
- 循环链表
- 有序表
- 二路归并算法:两个序列逐个对比,合适的拿出来,索引++,循环往复
- 快速排序算法:不断地划分两个区间,递归调用
- 直接插入算法:不断的将无序区数据插入有序区
- 基本算法题
- 增删查改
- 排序
- 递归
栈和队列
- 栈
- 特点:先进先出
- 存储结构
- 顺序栈
- 链栈
- 栈的应用
- 表达式求值
- 递归算法转化非递归算法
- 求解迷宫问题
- 队列
- 特点:先进后出
- 队列存储结构
- 顺序队
- 链队
- 特殊队列
- 循环队列
- 双端队列
- 应用
- 求解迷宫问题(求最短路径)
- 图层次遍历的非递归算法
串
- 串的特点
- 串的存储结构
- 顺序串
- 存储方法
- 基本运算
- 链串
- 存储方法
- 基本运算
- 串的模式匹配
- bf算法
- 目的:找出主串中模式串的位置
- 接口:主串,模式串
- 临时变量
- i用来遍历主串
- j用来遍历模式串
- 运算流程
- 遍历主串中,遍历模式串逐个对比,若不匹配则主串,模式串都回溯,若匹配则继续比对下一个直到模式串比对完,返回位置
- kmp算法
- 目的:找出主串中模式串的位置
- 接口:主串,模式串
- 临时变量
- next[]数组用来保证主串不回溯,模式串部分回溯
- i用来遍历主串
- j用来遍历模式串
- 运算流程
- getNext(t)获取next数组子函数
- 目的:获取next[]数组
- 接口:模式串
- 临时变量
- j用来遍历模式串
- k用来标记前缀后缀相同数目
- 运算流程
- 当tk==tj时,说明相同前后缀数目+1,j++;k++;next[j]=k;否则k=next[k],k回退继续对比。
- 遍历主串中,遍历模式串逐个对比,对比成功就下一个,不成功就按照next数组进行回溯j=next[j],继续对比直到结束,若模式串遍历完那么返回索引
- kmp改进算法
- 求nextval[]数组
- next数组的作用是回退,如果模式串回退到相同字符,等于无效回退,所以求nextval数组时,所有回退到相同字符情况产生连坐,他们的next值都是以第一个为准
- 当tk==tj时,说明相同前后缀数目+1,j++;k++;准备赋值nextval,再次判断tk==tj,如果相等,那么nextval[j]=next[k];否则正常执行nextval[k]=k
递归
- 递归相关概念
- 递归定义
- 直接递归(主要)
- 间接递归
- 何时使用递归
- 定义是递归的
- 数据结构是递归的
- 问题的求解方法是递归的
- 递归模型
- 递归出口
- 递归体
- 小问题(基本逻辑)
- 大问题和小问题的联系
- 递归执行过程
- 递归调用的实现
- 递归算法的设计方法
- 递归算法的设计步骤
- 假设出合理的小问题(基本逻辑)
- 建立小问题和大问题之间的递归关系
- 设置递归出口
- 基于递归数据结构递归算法设计
- 正整数(基本逻辑是加法)
- 单链表(基本逻辑是指针移动)
- 基于递归求解方法递归算法设计
- 迷宫问题(基本逻辑是试探一步)
数组
- 数组
- 数组的特点
- 多维数组的存储结构
- 以行序为主的存储结构
- 以列序为主的存储结构
- 特殊矩阵的压缩存储(掌握数列求和公式)(下标都从0开始)
- 对称矩阵压缩存储
- k=i(i+1)/2+j
- 上(下)三角矩阵压缩存储
- 上三角k=i(2n-i+1)/2+j-i
- 下三角k=i(i+1)/2+j
- k=n(n+1)/2
- 对角矩阵(带宽为3)
- k=2i+j
- 稀疏矩阵
- 定义特点
- 存储结构
- 三元组
- 节点(行号,列好,值)
- 三元组顺序表(行数,列数,节点数组)
- 十字链表
树和二叉树
- 树
- 定义相关术语
- 逻辑表示法
- 树型表示法
- 括号表示法
- 树的性质
- 树节点数等于度数和+1
- 度为m,高度为h的树最多有(m^h-1)/(m-1)个节点
- 度为m,第i层的树最多有m^(i-1)个节点
- 度为m,节点数为n树最小高度为:向上取整(log_m(n(m-1)+1))
- 节点数为n树最大高度为n-m+1
- 树的遍历方法
- 先根遍历
- 后根遍历
- 层次遍历
- 树的存储方法
- 双亲存储结构(顺序存储)
- 孩子链存储结构
- 孩子兄弟链存储结构(类似二叉树)
- 二叉树
- 二叉树定义
- 满二叉树和完全二叉树
- 二叉树的性质
- 叶子节点数等于双分支节点数+1:n0=n2 + 1
- 非空二叉树i层最多有2^(i-1)个节点
- 高度为h二叉树最多2^h-1
- n个节点二叉树最低高度为:向上取整(log_2(n+1))
- 完全二叉树性质
- i<=n/2,编号为i为分支节点
- n为奇数,n1=0,n偶数n1=1;关系到最后一个分支节点是否单孩
- i的左孩子为2i,右孩子为2i+1
- i的父母为向下取整i/2
- 二叉树的存储结构
- 二叉树顺序存储
- 二叉树链式存储
- 二叉树的遍历及其应用
- 先序遍历
- 中序遍历
- 后序遍历
- 层次遍历
- 二叉树的构造
- 先序+中序
- 后序+中序
- 线索二叉树
- 二叉树线索化
- 遍历线索二叉树
- 哈夫曼树
- 构造哈夫曼树
- 生成哈夫曼编码
- 二叉树与树
- 二叉树与树森林的转换:兄弟孩子链
图
- 图的定义和相关术语
- 图的存储结构
- 邻接矩阵
- 邻接矩阵结点
- n,e:顶点数,边数
- 顶点数组
- 边关系矩阵
- 顶点结点
- no 编号
- inf 信息
- 邻接表
- 邻接表结点
- 顶点数组
- n,e:顶点数,边数
- 顶点结点
- firstarc 第一个边链结点
- 边链结点
- adjvex 编号
- nextarc 下一个边链结点
- inf 信息
- 十字邻接表
- 邻接多重表
- 图的基本运算
- 图的遍历
- 深度优先(DFS)
- 接口:adjGragh *G,int v(起始节点的编号)
- 临时变量
- 全局变量 visited[]保存是否遍历过的信息
- arcNode *p遍历边结点
- 运算流程
- 循环+递归
- 读取第v个结点,设置visited数组
- 循环读取所有边链结点
- 若边链结点没有被读取,递归DFS(G,p->adjvex)
- 广度优先(BFS)
- 接口:adjGragh *G,int v(起始节点的编号)
- 临时变量
- 全局变量 visited[]保存是否遍历过的信息
- arcNode *p遍历边结点
- sqQueue *qu队列,保存的是序号
- int w 出队结点
- 运算流程
- 出队访问,进队所有邻接点
- 读取第v个结点,进队v
- 当队列不为空时循环
- 出队w,访问w,设置visited[w]
- 进队所有邻接点
- p访问第一个邻接点
- 当p不为空时循环所有边链
- 进队未被访问的节点
- 应用
- 生成树和最小生成树
- 普里姆算法prim:设定一个起始点,每次选距离最短的点
- 克鲁斯卡尔算法:每次选一个不产生回环的边
- 最短路径
- 广度遍历算法(不带权)
- 迪杰斯特拉算法(单源最短路径):每次确定一个点的最短路径(不适合含负权值)
- S集合:确定的最短路径的点的集合
- path[][]:点最短路径的前驱节点
- dist[][]:两点之间的路径长度
- 弗洛伊德算法(任意两点之间最短路径):每次添加一个中转节点,确定一个最短路径
- A[][]:保存两点的距离
- path[][]:点路径的前驱节点
- 拓扑排序(AOV图)
- 将所有没有前驱的节点遍历,并删除节点及其边
- 关键路径:拓扑图中最大长度的路径(AOE图)
- ve:事件(点)最早开始时间
- vl:事件(点)最迟开始时间
- e:活动(边)最早
- l:活动(边)最迟
- d:活动差值,为0的就是关键活动
查找
- 查找的基本概念
- 查找
- 平均查找长度
- 线性表的查找
- 顺序查找
- 二分查找
- 构造判断树
- 分块查找
- 树表的查找
- 二叉排序树
- 插入:作为叶子节点插入
- 删除:特殊情况同时存在左右子树,把左子树最大的节点提上来
- 查找
- 二叉平衡树
- 最高高度h与节点数n的关系
- h1=1,h2=2
- hk=h_(k-2)+h_(k-1)+1
- 前几个规律1,2,4,7,12,20
- 插入
- 作为叶子节点插入
- 调整
- LL,RR调整:失衡节点孩子上调
- RL,LR调整:失衡节点孙子上调
- 删除
- 当作二叉排序树删除
- 发现失衡后做调整LL,RR,RL,LR
- 查找
- B-树
- 插入
- 不超过界限直接插入
- 超过,加入后排序,把中间关键字提出,加入父母节点,两边分裂,成为其孩子。若父母也溢出,重复操作
- 删除
- 非叶子关键字:借最大的孩子到非叶子节点,然后删除叶子上孩子关键字,转换到删除叶子关键字
- 叶子关键字
- 满足条件直接删
- 不满足最低界限
- 自己借父母,父母借兄弟
- 兄弟都不够借,连同自己与兄弟拆父母的一个关键字合并
- 如果父母都不够借,把父母看成叶子节点重复操作
- 查找
- B+树
- 和B-树的区别
- 关键字的数量n的范围
- b-树,n的范围向上取整(m/2)-1到m-1
- b+树,2/m到m
- 子树数量
- b-数,n+1棵子树
- b+,n课一个关键字对应一个子树
- 节点作用
- b- 所有节点关键字不重复,关键字是存储地址
- b+ 非叶子节点只是索引作用,叶子节点的关键字才是存储作用,包含所有节点,并且有两个指针,一个用来遍历树结构,一个用来遍历顺序结构
- 哈希表的查找
- 哈希函数的构造
- 装填因子:n/m
- 除留余数法:p是小于等于m的素数
- 解决哈西冲突的方法
- 开放定址法
- 线性探测法
- 平方探测法
- 拉链法
内排序
- 排序的基本概念
- 稳定性
- 插入排序:每次将无序区第一个插入有序区
- 直接插入算法
- 接口:无序数组A,数组长度n
- 临时变量
- i遍历整个序列代表代插入关键字,j遍历有序区,temp保存带插入无序关键字
- 运算过程
- 两层循环,一层循环整个序列,二层循环遍历有序区插入
- 一层循环内,先判断a[i]与前一个是否无序,若无序那就排序,temp保存关键字,j=i-1,进入二层循环,从后向前找到合适位置,并后移关键字一位,然后temp放入
- 折半插入算法:只是第二层循环用的是折半查找
- 接口:无序数组A,数组长度n
- 临时变量
- i遍历整个序列,j用来实现后移插入,temp保存关键字,low,high,mid实现折半查找
- 运算过程
- 两层循环,一层循环整个序列,二层有两个子循环,一子循环为折半查找,二子循环为后移插入
- 一层循环内,先判断a[i]与前一个是否无序,若无序那就排序,temp保存关键字,low=0,high=i-1;进入二层循环,当low<=high的时候,mid=(low+high)/2,折半查找根据不同情况更改low或high的值,跳出循环说明找到位置,用j进行后移插入
- 希尔排序:使用直接插入算法实现分组排序,组越分越小,最后完全有序
- 交换排序
- 冒泡排序:从后往前,挨个比较交换,每次排出一个最小的,前面为全局有序区
- 接口:无序数组A,数组长度n
- 临时变量
- i表示i次遍历排出i个有序数列,j用来从后往前比较交换
- 运算过程
- 两层循环,一层用i表示i次排序,j用来从后向前直到i那里进行交换
- 快速排序:每次将一个基准排到正确的位置,以此为基准划分左右两块区域,递归调用快速排序算法
- 接口:无序数组A,low,high待排序区间
- 临时变量
- int pivot基准
- 运算过程
- 一层循环里面嵌套递归
- 当low<high时循环,排序第一个关键字并获取基准,根据基准递归调用快速排序左右子序列
- 划分函数
- 接口:无序数组A,low,high
- 返回值:基准物理位置
- 临时变量
- pivot基准保存待排序的基准关键字
- 运算过程
- 两层循环,一层左右遍历序列,二层用来左右横跳
- 先保存第一个关键字为基准,当low<=high开始循环,先从后往前找到一个小于基准的往前放,然后从前往后找一个大于基准的往后放,最后跳出循环剩下的位置放基准,返回基准位置
- 选择排序:每次选择一个最大或最小的放进全局有序区,
- 简单选择排序:每次从后面找到一个最小的,往前放
- 接口:无序数字A,长度n
- 临时变量:i代表有序区,j遍历无序区,min保存最小下标
- 运算过程
- 两层循环,一层遍历n遍,二层遍历无序区找最小
- 当i<n循环,min取i,用j从后向前循环,若遇到比min还小的,min取而代之,循环完,发现min值改变,交换a[i],a[min]
- 堆排序:将数组看成满二叉树的顺序存储结构,先从最后一个分支节点逐个筛选上浮,然后或得一个大根堆,将最大值根与最后一个叶子节点交换,然后再次对根节点进行筛选使之成为大根堆
- 接口:无序数组A,长度n
- 临时变量:
- i用来循环建立初始根堆,以及逐次的根节点交换后排序
- 运算过程:
- 先建立大根堆,i初始为n/2表示最后一个分支节点,当i>=0时i–从后向前逐个进行筛选操作sift(a,i,n),形成大根堆
- 然后交换根节点和最后一个叶子节点,对根节点进行筛选sift(a,1,i-1),循环i=n,i>1,i–从后向前,每次算拍好一个最大值,
- 筛选函数sift:先保存待筛选关键字为temp,找出他的最大的一个孩子与父母对比,若比父母大则和父母交换,若破坏了自身大堆性则循环比较孩子和父母的关系,正常则跳出,这时找到temp的位置放入
- 接口:无序数组a,low,high排序区间
- 临时变量:
- i用来表示父母和最后的位置,j表示孩子,temp保存待筛选关键字
- 运算过程:
- i=low,j=2*i,temp=a[i]
- 一层循环调整大根堆并找到带筛选关键字的位置,先比较孩子大小,若孩子比父母大,a[i]=a[j]进行替换,若正常跳出循环,这个循环一直进行到正常,保证替换后的都是大根堆,最后i表示筛选后的位置,a[i]=temp;
- 归并排序:不断二路基本归并,归并的长度2的倍数递增直到为序列长度,需要一个额外的数组
- 二路归并
- 接口:无序数组A,low,mid,high表示归并的区间
- 临时变量:r1接受比较后的序列,i,j遍历二路,k遍历r1
- 运算过程:
- 一层循环分别比较二路,哪边小放入r1
- 将二路剩下录入r1
- r1反过来给r,销毁r1
- 基数排序:根据基数排序,排位数次,重要性从小到大的排序
- 算法对比
- 插入排序
- 简单插入
- 折半插入
- 希尔排序
- 交换排序
- 冒泡排序
- 快速排序
- 选择排序
- 简单选择排序
- 堆排序
- 归并排序
- 基数排序
- 时间复杂度
- 初级算法都是n^2
- 改进算法都是nlogn
- 希尔排序和基数排序特殊
- 插入和冒泡排序有最好情况,快速排序有最差情况为n^2
- 空间复杂度
- 快速排序:log_2 n
- 二路归并: n
- 基数:r
- 稳定性
- 直,冒,归,基稳定
- 全局有序
- 交换排序和选择排序