图的基础相关算法有BFS,DFS,拓扑排序, 强连通分支,kruskal,prim,Bellman-Ford,Dijkstra。这些算法思想不难,就是代码容易忘记,所以将代码写在这里,以备复习。本文的代码都用邻接表结构。
图的邻接表结构定义:
struct Edge
{
int id;
Edge* pNext;
};
struct Vertex
{
int id;
Edge* pAdj;
};
struct ALGraph
{
vector<Vertex> vec;
};
BFS:
void BFS(const ALGraph& g, int k)
{
int size = g.vec.size();
vector<int> visit(size, 0);
queue<int> que;
que.push(k);
while (!que.empty())
{
int i = que.front();
que.pop();
visit[i] = 1;
Edge* p = g.vec[i].pAdj;
while (p != NULL)
{
if (visit[p->id] == 0)
{
visit[p->id] = 1;
que.push(p->id);
}
p = p->pNext;
}
}
}
DFS:
void DFS_TR(const ALGraph& g, int k, vector<int>& s, vector<int>& f, int& time, vector<int>& visit)
{
visit[k] = 1;
s[k] = ++time;
Edge* p = g.vec[k].pAdj;
while (p != NULL)
{
if (visit[p->id] == 0)
DFS_TR(g, p->id, s, f, time, visit);
p = p->pNext;
}
f[k] = ++time;
}
void DFS(const ALGraph& g)
{
int size = g.vec.size();
vector<int> visit(size, 0);
vector<int> s(size, 0);
vector<int> f(size, 0);
int time = 0;
for (int i = 0; i < size; ++i)
{
if (visit[i] == 0)
DFS_TR(g, i, s, f, time, visit);
}
}
拓扑排序:借助DFS,将f[]按照逆序输出即可
void DFS_TR(const ALGraph& g, int k, vector<int>& s, vector<int>& f,
int& time, vector<int>& visit, stack<int> stk)
{
visit[k] = 1;
s[k] = ++time;
Edge* p = g.vec[k].pAdj;
while (p != NULL)
{
if (visit[p->id] == 0)
DFS_TR(g, p->id, s, f, time, visit, stk);
p = p->pNext;
}
f[k] = ++time;
//先访问完的节点先入栈
stk.push(k);
}
void DFS(const ALGraph& g, stack<int>& stk)
{
int size = g.vec.size();
vector<int> visit(size, 0);
vector<int> s(size, 0);
vector<int> f(size, 0);
int time = 0;
for (int i = 0; i < size; ++i)
{
if (visit[i] == 0)
DFS_TR(g, i, s, f, time, visit, stk);
}
}
void Topo(const ALGraph& g)
{
stack<int> stk;
DFS(g, stk);
while (!stk.empty())
{
cout << stk.top() << endl;
stk.pop();
}
}
SCC:强连通分支,运用两次DFS
void DFS_TR_G(const ALGraph& g, int k, vector<int>& s, vector<int>& f,
int& time, vector<int>& visit, stack<int> stk)
{
visit[k] = 1;
s[k] = ++time;
Edge* p = g.vec[k].pAdj;
while (p != NULL)
{
if (visit[p->id] == 0)
DFS_TR(g, p->id, s, f, time, visit, stk);
p = p->pNext;
}
f[k] = ++time;
//先访问完的节点先入栈
stk.push(k);
}
void DFS_G(const ALGraph& g, stack<int>& stk)
{
int size = g.vec.size();
vector<int> visit(size, 0);
vector<int> s(size, 0);
vector<int> f(size, 0);
int time = 0;
for (int i = 0; i < size; ++i)
{
if (visit[i] == 0)
DFS_TR_G(g, i, s, f, time, visit, stk);
}
}
void DFS_TR_GT(const ALGraph& g, int k, vector<int>& s, vector<int>& f,
int& time, vector<int>& visit)
{
visit[k] = 1;
s[k] = ++time;
Edge* p = g.vec[k].pAdj;
while (p != NULL)
{
if (visit[p->id] == 0)
DFS_TR(g, p->id, s, f, time, visit, stk);
p = p->pNext;
}
f[k] = ++time;
}
int DFS_GT(const ALGraph& g, stack<int>& stk)
{
int size = g.vec.size();
vector<int> visit(size, 0);
vector<int> s(size, 0);
vector<int> f(size, 0);
int time = 0;
int res = 0;
while (!stk.empty())
{
int i = stk.top();
stk.pop();
if (visit[i] == 0)
{
++res;
DFS_TR_GT(g, i, s, f, time, visit);
}
}
return res;
}
void SCC(const ALGraph& g)
{
stack<int> stk;
DFS_G(g, stk);
//计算g的转置图,这步很简单用伪代码,设gt为g的转置
compute gt;
int res = DFS_GT(gt, stk);
}