算法导论(九)——图
广度优先搜索(Breadth First Search):从一个顶点开始,搜索所有可到达的顶点。它将邻接未访问点都加入队列,在对当前访问点进行邻接搜索。从图的某个顶点v0出发,在访问v0之后,依次搜索访问v0的各个未被访问过的邻接点w1,w2,…。然后顺序搜索访问w1的各未被访问过的邻接点,w2的各未被访问过的邻接点,…。——》使用队列
【类似二叉树的层次遍历】
virtual void bfs(int v,int reach[],int label) {
arrayQueue<int>q(10);
q.push(v);
reach[v]= label;//from v
while(!q.empty()) {
//delet ewhich had been labeled
int w = q.front();
q.pop();
//adjacent vertex
vertex Iterator<T>*iw = iterator(w);
int u;
while((u=iw->next())!=0){
if(reach[u] == 0) {
q.push(u);
reach[u]= label;
}
}
delete iw;
}
}
在实际操作时,针对邻接加权有向图 (a[w][u])或链接图(u=aList[w].firstNode,u=u->next),采用定制版的代码能提高效率,主要改动是搜索邻接w的未访问的顶点部分。参考P409.
深度优先搜索(Depth First Search):它将邻接未访问点当作候选,从某个点开始搜索,终止时返回上一级搜索。
【类似二叉树的前序遍历】
void dfs(int v, int reach[], int label) {
graph<T>::reach= reach;
graph<T>::label= label;
rDfs(v);
}
void rDfs(int v){
reach[v]= label;
vetexIterator<T>*iv = iterator(v);
intu;
while((u = iv->next) != 0) {
rDfs(u);
}
deleteiv;
}
详细代码见:http://blog.chinaunix.net/uid-26548237-id-3483650.html
比较:两种方法具有相同的时间和空间复杂性,不过它们的最好和最坏情况恰好相对。深度优先搜索效率更高用得更多。
最短路径算法,
1. 单源路径——Dijkstra Alg【最短路径的子路径也是最短路径】局限于边的权值非负的情况
Floyd-Warshall算法:是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。Floyd-Warshall算法的时间复杂度为O(N3),空间复杂度为O(N2)。【十字交叉法】
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html
差分约束系统:http://blog.youkuaiyun.com/consciousman/article/details/53812818
Johnson算法:能在O(V2lgV+VE)的时间内解决所有结点对最短路径问题,对于大型稀疏图来说这是一个很好的算法
总结:http://blog.youkuaiyun.com/gqtcgq/article/details/45621591
面试常见问题:
1. 判断图是否存在环G=(V,E)
无向图:
① i)如果E>=V,则根据图论知识可直接判断存在环路。(证明:如果没有环路,则该图必然是k棵树 k>=1。根据树的性质,E=V-k)
ii)如果E<V,
1.求出图中所有顶点的度,
2.删除图中所有度<=1的顶点以及与该顶点相关的边,把与这些边相关的顶点的度减一
3.如果还有度<=1的顶点重复步骤2
4.最后如果还存在未被删除的顶点,则表示有环;否则没有环 复杂度O(E+V),
注:初始时刻统计所有顶点的度的时候,复杂度为(V + E),最差的复杂度就为O(EV)了。
②遍历整图,找到连通域P个,若 E + P > V,则原图有环,否则无环
③ DFS搜索图,在遍历的过程中,发现某个节点有一条边指向已经访问过的节点,并且这个已访问过的节点不是当前节点的父节点,则表示存在环。该算法的复杂度为O(V)。
为防止环重复计算,将节点分为白、灰、黑三种状态。
【http://blog.youkuaiyun.com/u010040029/article/details/52861473】
有向图:
①拓扑排序,若不能完成则含有环
计算图中所有点的入度,把入度为0的点加入栈;如果栈非空:( 取出栈顶顶点a,输出该顶点值,删除该顶点,从图中删除所有以a为起始点的边,如果删除的边的另一个顶点入度为0,则把它入栈);如果图中还存在顶点,则表示图中存在环;否则输出的顶点就是一个拓扑排序序列
②强连通域(对于一个图的某个子图,该子图中的任意u->v,必有v->u)
③改进的DFS。将深搜的点加一个特殊标记,如果从当前的点往下搜的时候,发现了这个特殊标记,立刻判定有环。【http://blog.youkuaiyun.com/panhe1992/article/details/8366466】
或者是每个节点标记成白、灰、黑三种状态,按照节点标记为黑色的时间,越先标记为黑色,在拓扑序列中越靠后(栈) 【http://blog.youkuaiyun.com/u010040029/article/details/52861473】