图论基础

来源:互联网 发布:启动子数据库 编辑:程序博客网 时间:2024/04/29 19:03
图的表示
常用的两种方法:
邻接表与邻接矩阵

每一个点对应一个集合set(邻接表),存储与此点相连的点。
1.
-)点用连续存储
  a. 邻接表用连续存储表 
  b. 邻接表用链式表  
List neighbors[max_size];

二)点与邻接表都用链式表
class Edge{
Vertex *end_point;  //边的终点
Edge *next_edge;    //邻接表的下一条边 
}   

class Vertex{
Edge *first_edge;         // 邻接表的第一条边
Vertex *next_vertex;      //  下一个点
         

class digraph
{
Vertex *first_vertex;
}

2. 固定集合大小max_set, 看成是bit string, 可以用STL中的bitset.  其实质上是下面的邻接矩阵.


邻接矩阵:
或者干脆用二维数组。
bool adjcency[max_size][max_size];
当表示无向图时有adjcency[v][w]=adjcency[w][v];
  表示有向图时, adjcency[v][w]表示图中是否有从v到w的边.


以上方式都可以表示边的权,
例如用链式表时,可在Edge加个变量weight。
List的Record包含权值与点的标号。
而邻接矩阵就用Record代替bool。

图的遍历
DFS(深度优先搜索)
递归算法
visit(V);
for(each vertex w adjacent to v)
  traverse(w);

1,图可能有回路的,为防止死循环,需要设置是否已经访问标记。
2,图可能不连通,需要对每一个点都进行DFS。

template <int max_size>       // 注意template奇怪用法
void Digraph<max_size>::depth_first(void (*visit)(Vertex &)) const

{
   bool visited[max_size];
   Vertex v;
   for (all v in G) visited[v] = false;
   for (all v in G) if (!visited[v])
      traverse(v, visited, visit);
}


template <int max_size>
void Digraph<max_size>::traverse(Vertex &v, bool visited[],
                                 void (*visit)(Vertex &)) const
/*
Pre:  v is a vertex of the Digraph.
Post: The depth-first traversal, using function *visit, has been completed
      for v and for all vertices that can be reached from v.
Uses: traverse recursively.
*/
{
   Vertex w;
   visited[v] = true;
   (*visit)(v);
   for (all w adjacent to v)
     if (!visited[w])
        traverse(w, visited, visit);
}

BFS(广度优先搜索)
队列+标记

拓扑排序(有向无回路图acyclic)
每个点出现在它的后继之前。
DFS:
递归: 找到没有后继的节点放到后面。
O(V+E)

BFS:
维护一个数组,记录每个点的前继的数目。先双重循环初始化其前继数目,
将前继数目为0的插入到拓扑队列中去
BFS: 当结点前继数目为0时,  说明此结点可以插入到拓扑序列中去, 然后一个循环相应的前继数目减一。

单源最短路径(权非负)
Dijkstra
贪心: 每次将到当前点集合中未访问的距离最短的节点加入到当前点集合中