数据结构题型
- 概念
- 应用题
- 3 时间/空间复杂度分析
- 4 stack和queue中数据的出入顺序
- 5.1 BST的插入/删除
- 5.2 Huffman树的构造
- 5.3 Heap的构造
- 5.4 二叉树的各种遍历
- 5.5 基于遍历数列构造二叉树
- 6.1 树的存储表示
- 6.2 树和二叉树的转换
- 7 shellsort / bubble sort / quicksort / heapsort / radix sort 的排序过程
- 9 hash表的构造(基于不同的哈希函数和冲突解决方式)及分析
- 10 2-3 tree / B-tree / B+Tree的构造,insert / delete操作
- 11.1 图的存储方式(Adjacent list/matrix)
- 11.2 DFS/BFS遍历过程,不同的拓扑排序算法过程
- 11.3 单源最短路径single-source (Dijkstra算法) 的构造
- 11.4 MST最小支撑树 (Prim/Kruskal算法) 的构造
- 编程题
四川大学数据结构与算法课程重点题型2023
概念
1-2 chapter
data type:a type together with a collection of operations to manipulate the type.
一个类型以及用于操作该类型的操作集合。
ADT(abstract data type):the realization of a data type as a software component.
数据类型作为软件组件的实现。
data structure:the implementation for an ADT.
problems:a function or a mapping of inputs to outputs.
输入到输出的函数或映射。
algorithms:a recipe for solving a problem whose steps are concrete and unambiguous.
解决问题的方法,步骤具体且明确。
programs:an instantiation of an algorithm in a programming language.
编程语言中算法的实例化。
set:a collection of distinguishable members or elements.
集合:可区分的成员或元素的集合。(不能有重复成员)
recursion:it calls itself to do part of its work.
递归
3 algorithm analysis
asymptotic algorithm analysis:estimate the resource consumption of an algorithm.
渐近算法分析:估计算法的资源消耗。
growth rate:the rate at which the cost of the algorithm grows as the size of its input grows.
算法成本随着其输入大小的增长而增长的速率。
不同速率例子:(
T
(
n
)
T(n)
T(n),n为输入数据数量)
n\T(n) | log n \log n logn | n n n | n 2 n^2 n2 |
---|---|---|---|
16 | 4 | 2 4 2^4 24 | 2 8 2^8 28 |
256 | 8 | 2 8 2^8 28 | 2 16 2^{16} 216 |
1024 | 10 | 2 10 2^{10} 210 | 2 20 2^{20} 220 |
best/worst/average case:for different input, running time/space is short/long/average
upper/lower bound
上/下限:算法的最高/最低增长率,即最糟情况和最好情况
big-Oh/big-Omega/Theta notation:describes an upper bound/lower bound/when the upper and lower are the same
上限符号:
O
(
g
(
n
)
)
O\left(g(n)\right)
O(g(n))
下限符号:
Ω
(
g
(
n
)
)
\varOmega \left(g(n) \right)
Ω(g(n))
上限下限一样时:
Θ
(
g
(
n
)
)
\varTheta \left(g(n) \right)
Θ(g(n))
4 list
list:a finite, ordered sequence of data items
有限、有序的数据项序列
array-based list:顺序表
(singly/doubly)linked list:单/双链表
(array-based, linked)stack:顺序表/链表栈
(array-based, circular, linked) queue:顺序表/循环/链表队列
FIFO :先进先出
LIFO :后进先出
5 binary tree
pre-/in-/post-order traversal:前序/中序/后序遍历 NLR/LNR/LRN
level-order(Breadth-First) traversal:层序遍历(也称为广度优先遍历),按照树的层次,从上到下,从左到右的顺序访问每个节点
full/complete binary tree:没有或有两个子代/除最后一层外全满,最后一次从左到右添加子代
height/depth/level of a binary tree:层数(包括根)/深度(根为0,向下一次+1)/层级:从根节点到该节点的唯一路径上的边的数量。(大小与深度相等)
full binary tree theorem:满二叉树定理:叶子结点数
n
0
n_0
n0=内部结点数
n
2
n_2
n2+1
BST:二叉查找树,满足leftchild
<
<
<root
⩽
\leqslant
⩽rightchild
Huffman tree:哈夫曼树
heap:堆,是完全二叉树,分为大顶堆(root大于两个子结点)和小顶堆(root小于两个子结点)
priority queue :优先队列,由堆实现,先取优先级高的就用大顶堆
6 general trees
traversal:树的遍历,包括前序和后序遍历
Equivalence classes:并查集:将成员分配到不相交集合的问题
7 internal sorting 0
各种排序算法的基本实现思想
数据初始顺序对各排序算法时间的影响
各算法的best/worst/average case时间复杂度
各排序算法的稳定性
3个时间复杂度为
Θ
(
n
2
)
\varTheta \left(n^2 \right)
Θ(n2)的排序
排序 | insertion | bubble | selection |
---|---|---|---|
基本思想 | 每个数依次向前插入 | 依次比较相邻的元素 | 依次找到最大/小的数放在前/后面 |
比较: | |||
best case | Θ ( n ) \varTheta \left(n \right) Θ(n) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) |
average | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) |
worst case | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) |
交换: | |||
best case | 0 0 0 | 0 0 0 | Θ ( n ) \varTheta \left(n \right) Θ(n) |
average | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n ) \varTheta \left(n \right) Θ(n) |
worst case | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n ) \varTheta \left(n \right) Θ(n) |
稳定性 | ✔ | ✔ | ❌ |
4个时间复杂度为 Θ ( n log ( n ) ) \varTheta \left(n\log(n) \right) Θ(nlog(n))的排序
排序 | shellsort | mergesort | quicksort | heapsort |
---|---|---|---|---|
基本思想 | ||||
比较: | ||||
best case | Θ ( n ) \varTheta \left(n \right) Θ(n) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | |
average | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | |
worst case | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | |
交换: | ||||
best case | 0 0 0 | 0 0 0 | Θ ( n ) \varTheta \left(n \right) Θ(n) | |
average | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n ) \varTheta \left(n \right) Θ(n) | |
worst case | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n 2 ) \varTheta \left(n^2 \right) Θ(n2) | Θ ( n ) \varTheta \left(n \right) Θ(n) | |
稳定性 |
8 File processing and external sorting
buffer pool:缓存的集合,介于硬盘与内存之间
track/sector/cluster:在硬盘存储中,磁道(Track)是硬盘表面的同心圆,扇区(Sector)是磁道上的一个弧段,是硬盘的最小存储单位,通常是512字节或4096字节。柱面(Cylinder)是由具有相同编号的磁道形成的一个圆柱。
Golden Rule of File Processing:应该是少访问外存
external sorting:外排序,处理的数据不能一次装入内存,只能放在读写较慢的外存储器上。
run:已经排序的数据段,在生成初始归并段的过程中,会产生多个run,然后在归并阶段,将这些run合并成一个完全排序的文件
replacement selection:置换选择排序,利用小顶堆,每次读入一个数据,输出小顶堆中最小的数据,再整理成小顶堆
9 Searching
sequential search, binary search, hashing, collision,Open hashing, Closed hashing, Probe function, load factor,HT
10 Indexing
indexing, primary/secondary key, Linear indexing,2-3 tree, B-tree, B+Tree ,B数分析
11 Graphs
path, cycle, connected component连通分量:一个子图,complete graph,
BFS,DFS,DAG有向无环图, MST
应用题
3 时间/空间复杂度分析
例:
算法从数组的第一个元素开始,逐个检查每个元素,直到找到目标元素或者检查完所有元素。
上界(Big Oh): 在最坏的情况下,目标元素可能在数组的最后一个位置,或者可能根本不在数组中。在这种情况下,需要检查数组中的每一个元素。因此,最坏情况的时间复杂度是 O(n),其中 n 是数组的长度。
下界(Big Omega): 在最好的情况下,目标元素可能就在数组的第一个位置。在这种情况下,只需要检查一个元素。因此,最好情况的时间复杂度是 Ω(1)。
4 stack和queue中数据的出入顺序
stack:LIFO
queue:FIFO
5.1 BST的插入/删除
插入操作:
1.如果树为空,则直接新增节点,赋值给根节点。
2.如果树不为空,按照二叉搜索树的性质查找插入的位置,插入新节点。如果插入的元素值小于当前节点的值,则将元素插入到当前节点的左子树;如果插入的元素值大于当前节点的值,则将元素插入到当前节点的右子树。
删除操作:
1.如果待删除的节点是叶子节点,直接删除即可。
2.如果待删除的节点只有左子树或右子树,则让待删除节点的子树成为待删除节点的父节点的子树,替代待删除节点的位置。
3.如果待删除的节点有左、右两棵子树,则令待删除节点的右子树最小结点(或左子树最大结点)替代待删除节点。
5.2 Huffman树的构造
每次找两个权重最小的结点进行合并
5.3 Heap的构造
堆的构造:从最后一个非叶子节点(i=n/2-1)开始,然后向上遍历到根节点(i>=0)。对于每一个节点 i,都调用 siftdown(i) 函数进行自上而下的堆化操作。
5.4 二叉树的各种遍历
N-root, L-left child, R-right child
遍历方法:1.Preorder: NLR, NRL
~~~~~~~~~~~~~~~~
2.Inorder: LNR, RNL
~~~~~~~~~~~~~~~~
3.Postorder: LRN, RLN (都是以N为基准)
5.5 基于遍历数列构造二叉树
由preorder和inorder 或 postorder和inorder可唯一地确定一个二叉树。
6.1 树的存储表示
1.List of Children 子结点表表示法
Val:结点名
Par:父结点的Index值
2.Left-Child/Right-sibling 左子结点/右兄弟结点表示法
Left:最左子结点位置指针
Right:右边第一个兄弟结点位置指针
3&4.Dynamic Node 两种动态结点表示法
6.2 树和二叉树的转换
树与二叉树之间的转换通常采用左孩子右兄弟的表示法。
树转换为二叉树:
加线:在所有的兄弟结点之间加一条线。
去线:树中的每个结点,只保留它与第一个孩子结点的连线,删除其他孩子结点之间的连线。
调整:以树的根结点为轴心,将整个树调节一下(第一个孩子是结点的左孩子,兄弟转过来的孩子是结点的右孩子)。
二叉树转换为树:
调整:将二叉树从左上到右下分为若干层。然后调整成水平方向。
加线:找到每一层节点在其上一层的父节点,加线。
去线:去除兄弟节点之间的连线。
7 shellsort / bubble sort / quicksort / heapsort / radix sort 的排序过程
shellsort
1.初始化间隔大小,例如:d=n/2。
2.将列表划分为间隔为d的多个子部分。
3.使用插入排序对这些子列表进行排序。
4.d/2取整(如10,5,3,1),重复步骤2,直到d=1,列表排序完毕。
bubble sort
1.依次比较相邻元素,使较大的元素下沉,比较n-1次
2.n-1,重复上述过程,直到列表排序完毕。
quicksort
1.选择任何元素作为枢轴pivot,并根据该枢轴将给定数组划分为两个子数组。
2.重复上述过程,直到每个子数组只有一个元素。
3.合并结果
heapsort
1.用数据构建一个大顶堆。
2.依次取出根元素,在堆中删除该结点,并重新下沉调整堆
3.重复上述过程,直到堆中没有元素。
radix sort
1.最大的元素的位数为排序次数
2.按个位从小到大排序,个位相同的元素不改变相对位置
~~~
2.1 创建一个长度为10的数组B,分别存放个位是0-9的元素的个数
~~~
2.2 数组中除第一个数外每个数依次变为自己与前一个数之和
~~~
2.3 创建一个大小与原数组A相同大小的数组C,从右向左取数组A中的元素,根据个位的大小放入与数组B对应大小的数组C位置中(如B中第2个数是3,对应个位为1,A中取到81,所以放到数组C的第3个位置)
3.位数向左移1位,重复上述过程,直到完成最大元素的位数的排序
9 hash表的构造(基于不同的哈希函数和冲突解决方式)及分析
hash functions
1.h(K)=K
2.h(K)=K mod P (P为空间上限)
(看题目提供)
collision resolution 冲突解决
1.open hash 冲突的元素放表外
2.close hash (open address) 冲突的元素放表内
~~~
2.1 bucket hashing 为每一个映射后的值留2个或更多空间,称为一个bucket,所以可以存2个或更多相同映射值的值,如果还有溢出,溢出的值全放入overflow数组。
~~~
2.2 Linear probing 原位置被占就向后依次找一圈
~~~
2.3 pseudo-random probing 伪随机 生成一组随机数列,每次依次加一个数
~~~
2.4 quadratic probing 平方 每次加
i
2
i^2
i2
~~~
2.5 double hashing 双哈希 h(K)=h(K)+P(k,i) ; p(k,i)=i*
h
2
(
K
)
h_2(K)
h2(K)
10 2-3 tree / B-tree / B+Tree的构造,insert / delete操作
2-3 tree
插入
1.找到子叶,空则插入
2.子叶没空,先插入再把中间的值向上插入,另两个值分成两个叶
3.向上的根满了,再取中间值向上插
B-tree
m order 的 B-Tree 每个内部结点有 m/2(向上取整) 到 m 个子代
插入:与 2-3Tree 类似
B+Tree
记录只存储在子结点,内部节点存储关键字,子结点若最多装n个记录,则最少装n/2个记录,否则与其他结点进行合并
插入:与 2-3Tree 类似
删除
1.子结点有大于 n/2 个数,直接删除
2.删除后数太少,向左右兄弟结点拿一个数,并修改根的值
3.删除后数太少,且不能向左右兄弟结点拿数,合并兄弟结点
11.1 图的存储方式(Adjacent list/matrix)
方式 | Adjacent list | matrix |
---|---|---|
有向图 | 每个边u->v只存储一次,在u的邻接列表中 | 每个边u->v只存储一次,在u行v列的邻接矩阵中 |
无向图 | 每个边uv存储两次,一次在u的邻接列表中,一次在v的邻接列表中 | 每个边u->v存储两次 |
11.2 DFS/BFS遍历过程,不同的拓扑排序算法过程
DFS 深度优先搜索
从一个点开始一直向前走到头,再后退直到遇到未走的岔路,再从这个岔路继续向前,直到遍历所有结点
BFS 广度优先搜索
从一个点开始依次找到所有与它相邻的结点存储在数组中,再分别依次找数组中的点相邻的点,直到遍历所有结点
Topological 拓扑排序
法1.先用DFS,后退时打印,最后再全部倒过来
法2.从无前驱的点开始,删除走过的点和相连的边,继续选无前驱的点
11.3 单源最短路径single-source (Dijkstra算法) 的构造
1.从源节点开始,将其当前距离标记为0,其余节点的当前距离标记为无穷大。
2.选择一个未访问的节点,该节点的当前距离最小,并将其标记为当前节点。
3.访问当前节点的所有邻居。如果找到更短的路径,则更新它们的临时距离。
4.将当前节点标记为已访问。
5.如果所有可达节点都已访问,或者已经到达目标节点,则算法结束。否则,返回步骤2。
11.4 MST最小支撑树 (Prim/Kruskal算法) 的构造
Prim算法
任取一点s为根,向树上加点w,所有点分为2个集合:树上&非树上,每次选两个集合之间最短边对应的点加入树
Kruskal算法
从最短的边开始加,且确保不产生回路
编程题
4 array-base, linked下的list/stack/queue的各种操作
Array-based Lists
private:
int maxSize;//表总空间
int listSize;//表使用长度
int curr;//当前位置
E* listArray;//表元素
Singly Linked List
class node
{
public:
T data; //结点元素
node* next; //指向后面的指针
node()
{
data = 0;
next = NULL;
}
node(T d, node* next = NULL)
{
data = d;
next = next;
}
};
class List:public node
{
private:
node* head;
node* tail;
node* curr;
int size;
}
5.1 二叉树的遍历
class BinNode
{
private:
E it;
BinNode* lc;
BinNode* rc;
public:
BinNode()
{
lc = rc = NULL;
}
BinNode(E e, BinNode* l, BinNode* r)
{
it = e;
lc = l;
rc = r;
}
}
class BinTree
{
private:
BinNode* root;//根结点
public:
//构造函数
BinTree()
{
root = NULL;
}
//析构函数
~BinTree()
{
clear(root);
}
5.3 BST的查找
7 insert/selection/bubble/heap/quick sort算法
class heap {
private:
E* Heap;
int maxsize;
int n;
//堆的下沉调整
void siftdown(int pos) {
while (!isLeaf(pos)) {
int lc = leftchild(pos);
int rc = rightchild(pos);
if ((rc < n) && Comp::prior(Heap[rc], Heap[lc]))
lc = rc;
if (Comp::prior(Heap[pos], Heap[lc]))
return;
swap(Heap[pos], Heap[lc]);
pos = lc;
}
}