基本概念
-
时、空复杂性 (Ω-下界、𝛩-确界、O-上界)及等级、RUNTIME CALCULATION
-
数据结构基本概念:
-
数据类型、对象、操作、数据结构
-
三大类数据结构:线性(堆栈、队列)、树、图
-
数据结构的物理表示方法:数组、链表
-
堆栈和队列(STACK AND QUEUE)
-
堆栈(STACK):
-
概念:在同一端插入和删除,FILO
-
表示:数组、链表
-
操作:入/出栈,空/满判断
-
-
队列(QUEUE)
-
概念:在一段插入而在另一端删除,FIFO
-
表示:数组、链表
-
操作:入/出队列,空/满判断
-
-
应用——表达式求值,EVAL,POSTFIX(后缀表达式)
拓展:表达式求值:
题解:AcWing 3302. 表达式求值 - AcWing
图(GRAPH)
-
基本概念:component,degree,connected,path
-
表示:邻接矩阵(adjacency matrix)、邻接表(adjancency list)/逆邻接表,DAG(directed acyclic graph,有向无环图),邻接多重表(adjacency multi-list)、十字链表(orthotropic list)
-
基本操作:DFS(depth-first search)、BFS(bread-first search)
-
图上的典型算法
-
最小生成树(minimum spanning tree):Prim(以点为中心) and Kruskal(以边为中心)
-
最短路径(shortest-path):Dijkstra Algorithm,unweighted shortest path
-
拓扑排序(Topological Sort)
-
网络流量问题(Network Flow Problems)
-
关键路径(Critical Path)
-
双连图/关节点(bi-connectivity/articulation points)
(DFS,LOW),bi-connected components
-
void DFS(Vertex V){ visited[V]=true; for(each W adjacent to V){ if(!visited[W]) DFS(W); } }//对于无向图的连通分量 void ListComponents(Graph G) { for(each V in G){ if(!visited[V]){ DFS(V); printf("\n"); } } }
双连通性(Biconnectivity)
-
v is an
ariculation point
if G’=DeleteVertex(G,v) has at least 2 connected components -
G is a biconnected graph if G is connected and has no articulation points
-
a biconnectivity component is a maximal biconnected subgraph
-
No edges can be shared by two more biconnected components. Hence E(G) is partitioned by the biconnected components of G
use DFS to find the articulation points in G
-
The root is an articulation point if it has at least 2 children
-
Any otehr vertex u is an articulation point if u has at least 1 child, and it is impossible to move down at least step and then jump up to u’s ancestor.
使用Tanjar 去寻找割点(也就是关节点:articulation point):需要定义两个数组——Low[n],Num[n]
Low(u)=min{Num(u),min{Low(w)|w is a child of u},min{Num(u,w)|(u,w)is a back edge}}
u is a articulation point:
-
u is the root and has at least 2 children
-
u is not the root, and has at least 1 child such that Low(child)≥Num(u)
也就是如果一个节点是关节点有两种可能:一种是它是根节点,且有两个及以上的子节点;第二种是非根节点,但他子节点的Low要大于等于他的Num,也就是他的子节点无法通过除了他的祖先节点到达,只能靠他,如果没有他,他的子节点就有没有依靠了,就无法被遍历了
HASH
-
基本思想:解决动态查找问题
-
hash函数的构造方法(hash function construction)
-
冲突处理方法(collision resolution):
-
开放地址法(open addressing):linear probing,quadratic probing
-
Chaining
-
Double hashing
-
Rehashing (再哈希)
-
冲突(collision):当两个关键字散列到同一个值
装填因子(load factor): 为散列表中的元素个数与散列表大小的比值
分离链接法(seperate chaining)(俗称:拉链法):将散列到同一个值的所有元素保留到一个表中
Note:Make the TableSize about as large as the number of keys expected (i.e. to make the loading density factor λ约等于1.(也就是说让装填因子=1是比较恰当的)
//Find Position Find(ElementType Key,HashTable H) { Position P; List L; L=H->TheLists[Hash(Key,H->TableSize)]; P=L->Next; while(P!=NULL && P->Element!=Key) P=P->Next; return P; } //Insert void Insert(){ Position Pos,NewCell; List L; Pos=Find(Key,H); if(Pos==NULL){//没有找到的话就选择插入 NewCell=malloc(sizeof(struct ListNode)); L=H->TheLists[Hash(Key,H->TableSize)]; NewCell->Next=L->Next; NewCell->Element=Key; L->Next=NewCell; } }
开放地址法(Open addressing)
关键函数:hi(X) = (Hash(X )+ F(i)) mod TableSize
-
线性探测法(linear probing):F(i)=i
-
插入和不成功的查找:1/2*(1+1/(1-λ)2)
-
成功的查找:1/2*(1+1/(1-λ))
-
一次聚集
-
-
平方探测法(quadratic probing):F(i)=i2
-
如果使用平方探测,且表的大小为素数,那么当表至少有一半是空的时候,总能够插入一个新的元素。可以通过证明前(tablesize/2)个备选位置是互异
Position Find(ElementType Key,HashTable H) { Position CurrentPos; int CollisionNum; CollisionNum = 0; CurrentPos=Hash(Key,H->TableSize); while(H->Thecells[CurrentPos].Info!=Empty && H->TheCells[CurrentPos].Element!=Key){ CurrentPos+=2*++CollisionNUm-1;//F(i)=F(i-1)+2i-1 if(CurrentPos>=H->TableSize)CurrentPos-=H->TableSize; } return CurrentPos; }
Legitimate合法的
-
二次聚集
-
-
双散列(double hashing):F(i)=i*hash2(X)
-
一般来说 hash2 (X)=R-(X mod R),其中R为小于TableSize的素数
-
-
再散列(rehashing):建立另外一个大约两倍大(大于两倍的第一个素数)的表,而且使用一个相关的新散列函数,扫描整个原始的散列表,插入新表中
-
NewTableSize为原表大小两倍后的第一个素数
-
什么需要再散列:
-
as soon as the table is half full
-
When an insertion fails (necessary)
-
when the table reaches a certain load factor
-
-