图论算法总结

一幅含有V个结点的图是一棵树的条件:1) 有V-1条边且不含有环;2) 有V-1条边且连通;3) 连通,但删除任意一条边都不连通;4) 无环图,但添加任意一条边都会形成环;5) 任意一对顶点间仅存在一条路径。

图的数据结构表示:

1) 邻接矩阵:使用V*V的矩阵,当顶点v和顶点w之间有边相连时,位置(v, w)处值为true

2) 边的数组:使用Edge类,内含有2个int实例变量

3) 邻接表数组:使用以顶点为索引的列表数组,其中每个元素都是和该顶点相邻的顶点列表,即一个链表。

boolean[] marked;
void dfs(Graph G, int v){
    marked[v] = true;
    count ++;
    for(int w : G.adj(v))  //G.adj为顶点v的所有邻接点
        if(!marked[w])
            dfs(G,w);
}

dfs可用于查找图中所有的连通分量及个数

for(int s=0; s<G.V();s++){
    if(!marked[s]){
        dfs(G,s);
        count++;   //一个新的连通分量
    }
}

void dfs(Graph G, int v){
    marked[v] = true;
    id[v] = count;  //每个点所在分量
    for(int w : G.adj(v))
        if(!marked[w])
            dfs(G,w);
}

dfs还可用于解决:

1) 图是否为无环图

class Cycle{
    boolean[] marked;
    boolean hasCycle;
    public Cycle(Graph G){
        marked = new boolean[G.V()];
        for(int s=0; s<G.V(); s++)
            if(!marked[s])
                dfs(G,s,s);
    }
    void dfs(Graph G, int v, int u){
        marked[v] = true;
        for(int w : G.adj(v))
            if(!marked[w])
                dfs(G,w,v);
            else if(w != u)
                //只要检测到v的邻接点被访问过,并且不是上一层dfs邻接到v的点,就说明环存在
                hasCycle = true;
    }
}

2) 区分图是不是二分图:使用dfs遍历,每次染色都将邻接点染成不同的颜色,如果出现已经遍历的点并且颜色相同,则说明染色失败,不是二分图。


欧拉图:能够一次性不重复走过所有边

哈密顿图:能够一次性不重复走过所有点

有向图的dfs以及bfs和无向图非常相似。

有向图dfs的应用:内存管理垃圾清理,每个顶点代表一个对象,每条边代表一个对象对另一个对象的引用,最后需要回收所有清理可达对象。


有向图拓扑排序:给所有顶点排序,使得所有的边都是由前面的点指向后面的点。

遍历顺序:

1) 前序:在调用dfs的第一步就将顶点压入队列;

2) 后序:在递归调用dfs后将顶点压入队列,也就是在一个顶点的所有邻接点都遍历完成后再加入队列;

3) 逆后序:和后序的加入顺序相同,但压入的是栈,不是队列。

而拓扑顺序就是逆后序的排列顺序。


最小生成树算法:

1) Prime算法:每一次都为树添加一条边,直至添加V-1条边,每次都将下一条连接树中的顶点与不在树中的顶点且权重最小的边加入树中。 每次将挑选边的两个点加入marked队列,同时将两个点对应的所有相邻边加入候选边集,下一次从候选边集合中挑选权重最小的边。

2) Kruskal算法:每次将所有边中的权重最小边加入,作为树中的一条边,直至所有的边正好连通整个图。

最短路径算法:

Dijkstra算法:使用数组distTo来保存到每个顶点的距离,起始点s初始化为0,其他点初始化为无穷大。通过广度优先遍历,更新每个点的最短距离。

猜你喜欢

转载自blog.csdn.net/u010358304/article/details/79575373