一、琐碎知识点
(一)基本概念、时间复杂度和空间复杂度
- 逻辑结构不管数据在计算机中的存储方式
- 数据在计算机内存中的表示是指() 数据的存储结构(存储结构也称物理结构)
- 通常要求同一逻辑结构中的所有数据元素具有相同的特性,这意味着( )。不仅数据元素所包含的数据项的个数要相同,而且对应数据项的类型要一致。
- 数据的基本单位是数据元素;数据的最小单位是数据项。
- 数据结构是相互之间存在一种或多种特定关系的数据元素的集合。
- 数据的逻辑结构是指各数据元素之间的逻辑关系
- 数据结构是带有结构的各数据元素的集合
- 判断时间复杂度和空间复杂度:从终止条件入手,如果for循环中嵌套着的变量与外层变量有关的话,可以按照最坏的情况来解决内层循环次数的问题,之后内层循环次数与外层循环次数相乘。
- Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)
- 数据的存储结构包括顺序结构和链式结构;数据的逻辑结构包括线性结构和非线性结构;
- 数据的存储结构反应了数据在计算机中的存储方式,而不是逻辑结构
- 哪个函数具有最慢的增长速度:做差,哪个差值最小,即为谁
(二)顺序表
- 线性表的最大优点就是随机存取,用数组表示的线性表可以随机存取
- 顺序表对于最后一个元素的删除和插入复杂度都是O(1)
- 一般来说每个元素长度为L的线性表第i个元素ai的存储位置为:
LOC(ai)=LOC(a1)+(i-1)*L
- 查找一个元素,平均需要移动元素的个数是(n+1)/2
- 插入/增加一个元素,平均需要移动元素的个数是n/2
- 删除一个元素,平均需要移动元素的个数是(n-1)/2
- 在顺序表中,逻辑上相邻的元素,其对应的物理位置也是相邻的
(三)数组、串、线性表
- string类型的数据在结尾处还是有' \0 '的
- 对数组元素赋初值的时候,不能省略列数,但是可以省略行数
- 求广义表的长度和深度:广义表的长度:最大括号中的逗号数加1或者最外层包含元素个数;广义表的深度:每个元素的括号重数+外部的1的最大值即所含括弧的重数
- tail就是从最外层看,除去第一个以外其余的元素;head就是从最外层看,第一个元素,而且去一层括号
(四)链表
- 链表所需要的空间和线性长度成正比
- 链式存储结构中,除自身结点信息外,还包括指针域,因此,存储密度小于顺序存储结构
- 在具有N个结点的单链表中,访问结点的时间复杂度是O(N),创建、插入、删除、清空、查询的时间复杂度是O(N)
- 与单链表相比,双链表的优点之一是顺序访问相邻接点更加灵活
- 看到底是要选择什么样的链表,这类题就是看需要找到的元素的位置在哪即可,删除和插入都要找到其前一个位置
- 合并两个单链表,时间复杂度为O(1)
- 在地址为.…的结点之前/之后、插入/删除某一个结点的话,时间复杂度为O(1);
- 在第 i 个结点之前/之后、插入/删除一个新结点,或者,删除第 i 个结点,时间复杂度为O(n);
- 在一个具有n个结点的有序单链表中插入一个新结点并仍然保持有序的时间复杂度是O(n);
- 在单链表中增加一个头结点的好处是:方便运算的实现和使空表和非空表统一处理
- 单循环链表注意,虽然是循环,但是只能往一个方向走
- 尾指针指向的是最后一个元素,所以对于单链表而言,如果想要找到最后一个元素的前一个的话,需要从头开始遍历
- 循环链表最主要的优点是:从表中任意结点出发,都能扫描到整个链表;顺序访问相邻结点更加灵活
(五)栈和对列
- 对于顺序栈而言,元素的插入、删除和访问都必须在栈顶进行
- 顺序栈和链栈都是后进先出
- 对于顺序栈栈而言,如果是空的话,栈顶和栈底指向同一个位置;但是,如果不是空的话,栈顶指向栈顶元素的上一个位置
- 链栈是无头结点的单链表,插入和删除都在链表头上
- 线性表、堆栈和队列的主要区别是:堆栈和队列都是插入和删除受约束的线性表
- 链对列(有头结点、头指针和尾指针的单链表),允许插入的一端为队尾,允许删除的一端为队头
- 循环队列队空的话:front=rear;队满的话:(rear+1)%maxsize=front;
- 循环队列插入了n个元素:Q.rear=(Q.rear+n)%MAXQSIZE;
- 循环队列删除了n个元素:Q.front=(Q.front+n)%MAXQSIZE;
- 循环队列长度:(Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
将中缀表达式转换为后缀表达式,相应的堆栈操作序列:
(1)如果栈为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
(2)栈内<栈外:栈外操作符入栈
(3) 栈内>栈外:栈内符合条件的操作符出栈之后,栈外操作符再入栈(同级后来的视为低优先级,也就是,比如已经有*,后来了一个/,那么/的优先级低于*,先应执行*出栈,然后/再入栈)
(4)遇到 ‘(’:直接入栈,“(”视为最低优先级的符号
(5)遇到 ‘)’:出栈所有操作符直达遇到 ‘(’
(6)符号和字母在两个栈中,出栈的符号都进入字母所在的栈中
问堆栈中的内容是符号,而不是字母
(六)树和森林
- 对于任何一种树,如果只有根的话,算是有1个结点或者是有一个叶子,而且深度也为1;层数/深度/高度都是从根节点开始算的,根节点是1,然后一个个往下加1;
- 对任何一棵二叉树,若它含有n0 个叶子结点、n2 个度为 2 的结点,则必存在关系式:n0 = n2+1
- 用二分查找法从n个有序数中查找某数,最坏情况下的比较次数是long2底n取整数部分+1
- 完全二叉树的深度为 log2底n的整数值 +1
- 树转化为二叉树或者是森林转化为二叉树;树/森林对应的二叉树,其左、右子树的概念已改变为: 左孩子,右兄弟
- 先、中、后序遍历是对于根而言的
- 完全二叉树只有倒数第二层上的结点的度数(每个结点有几个分支,度数即为几)可以小于2,其余每层上的结点的度数都等于2。
- 二叉搜索树(二叉排序树)将未排序的序列,按照“左小右大”的规律插入组建树
- 折半查找判定树一定是平衡二叉树,但是二叉搜索树不一定是平衡二叉树,虽然两者都是左小右大
- 折半查找判定树和二叉搜索树的中序遍历是按照从小到大的顺序排列
- 叶子结点不管是在哪种遍历方法中,它们的相对位置是不变的。先序遍历、中序遍历、后序遍历三个其实是相对根来说的,叶子结点左右遍历的顺序是不变的。
- 只有两个结点的树度为1
- 大顶堆和小顶堆
- 对于任何一棵树,结点总数=总分支数目+1
- 森林包含树的棵数=结点数-森林边数
- 如果某二叉树的前序和后序遍历刚好相反的话,那么该二叉树高度一定等于其结点数
- 对N(≥2)个权值均不相同的字符构造哈夫曼树,则树中任一非叶结点的权值一定不小于下一层任一结点的权值
- 哈夫曼树中一定没有度为1的结点
- 哈夫曼树中两个权值最小的结点一定是兄弟结点
- 经过哈夫曼编码后,求文本所占字节数也就是求带权路径长度
- 等长方式编码:有n个字符就是log2底n的长度,在求n个字符的带权路径长度的时候,叶子结点的路径长度均为log2底n
- 哈夫曼编码比采用等长方式的编码节省了多少位数,也就是求出各自的带权路径长度之后做差
- 一棵哈夫曼树的带权路径长度等于其中所有分支结点的权值之和,也就是除头结点外各节点的权值加和
- 哈夫曼树是带权路径长度最短的树,路径上权值较大的结点离根较近
- 哈夫曼树的结点个数不能是偶数
- 哈夫曼树是n个带权叶子结点构成的所有二叉树中带权路径长度最小的二叉树
- 在哈夫曼树中,任何一个结点它的度都是0或者2,没有度数为1的结点,结点数一定是奇数个,不能是偶数个。
- 当一棵具有n 个叶子结点的二叉树的WPL 值为最小时,称其树为哈夫曼树,其二叉树的形状不是唯一的
- 编码:左0右1,从树根到叶结点,经历的分支连起来就是编码序列
- 某字符出现的概率/频率为,可以将概率视为叶子的权值
- 哈夫曼树形状不止一种,有多种,但是带权路径长度一定是最小的。
- 哈夫曼树不一定是一棵完全二叉树
- 在二叉搜索树中插入一个新结点,总是插入到最下层,作为新的叶子结点
(七)图
-
图的深度优先搜索算法类似于二叉树的先序遍历
-
图的广度优先遍历类似于二叉树的层序遍历
- 生成树:一棵有n个顶点的生成树有且仅有n-1条边
- 生成森林:对非连通图,则称各个连通分量的生成树的集合为此非连通图的生成森林
- 邻接表和邻接矩阵:一个图中,有n条边,e个结点,那么:邻接矩阵的空间复杂度为O(n^2^),与边的个数无关。邻接表的空间复杂度为O(n+e),与图中的结点个数和边的个数都有关;设N个顶点E条边的图用邻接表存储,则求每个顶点入度的时间复杂度为O(N+E),设N个顶点E条边的图用邻接矩阵存储,则求每个顶点入度的时间复杂度为O(N方)
- 在任何图中,所有顶点的度数之和=边数的2倍,因此,所有顶点的度数之和一定是偶数
- 所有顶点的入度和=所有顶点的出度和
- 一般,对称矩阵看成无向,非对称矩阵看成有向
- 判断是否为连通图一般看不连接的两个点;如果是非强连通图,则其各个极大强连通子图称作它的强连通分量
- 假设已经判断出一个集合为强连通分量,那么再判断剩下的是否为强连通分量的时候,应该将已经判断出来的点和与其相关联的边删除掉
- 若无向图G =(V,E)中含N个顶点,要保证图G在任何情况下都是连通的,则需要的边数最少是(N-1)(N-2)/2+1
-
图可以没有边,但是顶点数一定不能为0
- 设无向图的顶点个数为N,则该图最多有N*(N-1)/2条边
- 如果G是一个有X条边的非连通无向图,那么该图顶点个数最少为多少?顶点数最少,所以也就是,如果X条边使某一个图构成完全子图,那么再多一个顶点,这个图就是一个非连通无向图了。所以N*(N-1)/2=X,所以顶点数为N+1
- 连通分量:极大的连通子图称为G的连通分量
- 有n个顶点的强连通图最多有n(n-1)条边,最少有n条边;强连通图是指一个有向图中任意两点v1、v2间存在v1到v2的路径及v2到v1的路径的图
-
图的最小生成树Prim算法和Kruskal算法;Prim算法(添加顶点);Kruskal算法(添加边):将权值从小到大排序,然后依次选取最小的边,如果构成圈则不取,如果没构成圈则取;
-
最短路径Dijkstra算法和Floyd算法;Dijkstra算法取、更新、换;
- 拓扑排序:从图中没有前驱的顶点中择一并输出(栈/队列);从图中“删除”此顶点及所有从其出发的弧(也就是相关的弧);重复上述两步,至图空(得一全序),或者当前图中不存在无前驱的顶点为止,后者代表我们的有向图是有环的,因此,也可以通过拓扑排序来判断一个图是否有环。
- 关键路径:整个项目的工期由关键路径来决定,图的关键路径上任意活动的延期都会引起工期的延长
- AOE网中的关键路径是从第一个事件到最后一个路径的最长路径
邻接表
不管怎样表示邻接表,都需要有顶点,有边数,邻接表头数组,邻接表链表,不管是怎么写,其实都是在创建这四者。
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode
{
Vertex AdjV; /* 邻接点下标 */
PtrToAdjVNode Next; /* 指向下一个邻接点的指针 */
};
/* 顶点表头结点的定义 */
typedef struct Vnode
{
PtrToAdjVNode FirstEdge; /* 边表头指针 */
} AdjList[MaxVertexNum]; /* AdjList是邻接表类型 */
/* 图结点的定义 */
typedef struct GNode *PtrToGNode;
struct GNode
{
int Nv; /* 顶点数 */
int Ne; /* 边数 */
AdjList G; /* 邻接表 */
};
typedef PtrToGNode LGraph; /* 以邻接表方式存储的图类型 */
(八)静态查找表和KMP算法
- 从目标字符串str中看是否有和子字符串ptr一样的部分。一般匹配字符串时,我们从目标字符串str(假设长度为n)的第一个下标选取和ptr长度(长度为m)一样的子字符串进行比较,如果一样,就返回开始处的下标值,不一样,选取str下一个下标,同样选取长度为n的字符串进行比较,直到str的末尾(实际比较时,下标移动到n-m)。这样的时间复杂度是O(n*m)
-
KMP算法:可以实现复杂度为O(m+n),KMP算法的特点是,在模式匹配时,指示主串的指针不会变小回溯
- 求解next值(重点是与要求的next值的前一位的值相等即可)
- nextval(每个都要与自己next值对应的位置的字母进行比较,不同则自己,相同则找到底的别人)
二、题目
1、抽象数据类型中基本操作的定义与具体实现有关。
答案:错误
抽象数据类型指的是一个数学模型以及定义在该模型上的一组操作,抽象数据类型的定义仅取决于它的一组逻辑特性 ,与其在计算机内部如何表示和实现无关。
2、
3、
4、
5、
a85也就是第8行有5个元素,所以1+2+3+4+5+6+7+5=33
以对角线为划分边界,不管是上三角还是下三角都要包括对角线。第8行的对角线是a[7][7]
6、
- 从A往外一层层扩展
- tail就是从最外层看,除去第一个以外其余的元素
- head就是从最外层看,第一个元素,而且去一层括号
7、
实在不会的话,其实可以代数试一试
8、
a[i][j] X:起始地址 m:矩阵行数 n:矩阵列数 k:每个元素所占的字节长度
列为主存时:Y=X+(m(j-1)+i-1)*k
行为主存时:Y=X+(n(i-1)+j-1)*k
所以Y=BA+(8*(8-1)+5-1)*3,所以选C
9、
10、
答案:C
解析;删除表中最后一个结点的话,需要找到的是最后一个结点的前一个,在最后一个结点之后插入一个新结点的话,需要找到最后一个结点。所以需要找到的是最后一个结点和最后一个结点的前一个。
A直接否定;B即使是有头指针,但是是循环单链表,只能向一个方向进行循环,所以不管是找到的是最后一个结点还是最后一个结点的前一个,都需要从头开始一个个找;C有尾指针,所以对于找到最后一个结点时间复杂度是O(1),只不过要想找到最后一个结点的前一个,时间复杂度是O(n);D与B同理
11、
并非所有的循环双链表都是最好的选择
12、
13、
由13和14可得,堆栈中的内容是符号,而不是字母
14、
15、
16、
17、
18、
最多需要的比较次数也就是树的高度这么多
19、
实在不会的话,可以代数做
20、
21、
22、
23、
- 设二叉树中度为0的叶子结点个数为n0,度为1结点个数为n1,度为2结点个数为n2,于是n0 + n1 + n2 = 1102。
- 根据二叉树性质:n0 = n 2 + 1,代入得到,2n2 + n1+1 = 1102
- 由于完全二叉树的n1 只能是0或者1(为什么完全二叉树中度为1的结点只能是1或0?如果从满二叉树中在最后一层自左向右砍掉的节点数是偶数,那么该完全二叉树中度为1的节点数就是0。如果砍掉的节点数是奇数,那么该完全二叉树中就有且仅有一个节点的度为1. )
- 为满足2n2 + n1 = 1101,n1 =1,因此n2 = 550。
- 由n0 = n 2 + 1得n0 = 551,即叶子个数是551个。
24、
25、
26、
27、
28、
答案:T
29、
30、
强连通图是指一个有向图中任意两点v1、v2间存在v1到v2的路径及v2到v1的路径的图
31、
32、
33、
34、
35、