以下内容主要参考了严蔚敏版的数据结构教材
以下算法求有向图的每一个强连通分量中的节点并把一个强连通分量中的所有节点放在一个集合中。算法包含两次深度优先搜索过程:
- 第一次深度优先搜索过程按照从弧尾到弧头的顺序深度优先搜索并按照节点的所有邻接点是否都访问完成的先后顺序对访问的节点顺序进行排序。也就是说数组 v e c t o r < i n t > f i n i s h e d N o d e ( g . g e t G r a p h N o d e N u m ( ) , 0 ) ; vector<int> finishedNode(g.getGraphNodeNum() ,\quad 0); vector<int>finishedNode(g.getGraphNodeNum(),0);的 i n d e x = 0 index=0 index=0的元素的值是最先其所有邻接点都访问完成的节点的索引。
- 第二次深度优先搜索按照
f
i
n
i
s
h
e
d
N
o
d
e
finishedNode
finishedNode数组元素的逆序进行深度优先搜索,也就是从节点
f
i
n
i
s
h
e
d
N
o
d
e
[
g
.
g
e
t
G
r
a
p
h
N
o
d
e
N
u
m
(
)
−
1
]
finishedNode[g.getGraphNodeNum()-1 ]
finishedNode[g.getGraphNodeNum()−1]开始进行深度优先遍历(这时是从弧头到弧尾的顺序)。这时一次深度优先遍历能访问到的所有节点就是有向图中一个强连通分量中的所有节点的集合。下一次深度优先遍历能访问到的所有节点就是有向图中下一个强连通分量中的所有节点的集合。
以下的测试程序在图4的例子进行测试。图5是其十字链表的数据结构。该结构是按照以下弧的输入顺序(见图1、图2、图3)调用函数 O L G r a p h : : c r e a t e G r a p h ( ) OLGraph::createGraph() OLGraph::createGraph()创建的。
![](https://i-blog.csdnimg.cn/blog_migrate/c27dc5a7e28f2cdced39debe5d6d8bb2.png#pic_center)
![](https://i-blog.csdnimg.cn/blog_migrate/f9232db591148810e724a0a5d67bc9c8.png#pic_center)
![](https://i-blog.csdnimg.cn/blog_migrate/4f03fe4d6606028901fd0763a0f0a3f4.png#pic_center)
![](https://i-blog.csdnimg.cn/blog_migrate/a307acbfd9d7c6bbb1d6017ca86da303.png#pic_center)
![](https://i-blog.csdnimg.cn/blog_migrate/b2654a1af8d49709384083ec5f5d48a2.png#pic_center)
//图的十字链表表示
//弧节点
class GraphArcNode
{
private:
int weight;
int tailIndex;
int headIndex;
GraphArcNode* nextTailArcNode;
GraphArcNode* nextHeadArcNode;
public:
GraphArcNode(int d = 0, int tail = 0, int head = 0, GraphArcNode* nextTailArc=nullptr, GraphArcNode* nextHeadArc = nullptr)
{
weight=d;
tailIndex=tail;
headIndex=head;
nextTailArcNode= nextTailArc;
nextHeadArcNode= nextHeadArc;
}
int getTailIndex()
{
return tailIndex;
}
int getHeadIndex()
{
return headIndex;
}
GraphArcNode* getNextTailArcNode()
{
return nextTailArcNode;
}
GraphArcNode* getNextHeadArcNode()
{
return nextHeadArcNode;
}
};
//图节点
class GraphNode
{
private:
int data;
GraphArcNode* firstTailArcNode;
GraphArcNode* firstHeadArcNode;
public:
GraphNode(int d = 0, GraphArcNode* firstTail=nullptr, GraphArcNode* firstHead=nullptr)
{
data = d;
firstTailArcNode= firstTail;
firstHeadArcNode = firstHead;
}
void settail(GraphArcNode* value)
{
firstTailArcNode=value;
}
void sethead(GraphArcNode* value)
{
firstHeadArcNode=value;
}
GraphArcNode* gettail()
{
return firstTailArcNode;
}
GraphArcNode* gethead()
{
return firstHeadArcNode;
}
};
//图的数据结构
class OLGraph
{
private:
vector<GraphNode> graphNodeSet;
int nodeNum;
int arcNum;
public:
OLGraph(int num1,int num2)
{
nodeNum = num1;
arcNum=num2;
}
void createGraph()
{
int inputData=0;
int tail = 0;
int head = 0;
GraphArcNode* arc = nullptr;
cout << "Please input " << nodeNum << " nodes data!!" << endl;
for (int i = 0; i < nodeNum; i++)
{
cout << "The data " << i << " :";
cin >> inputData;
graphNodeSet.push_back(GraphNode(inputData,nullptr, nullptr));
}
cout << "Complete the data element input!! " << endl;
cout << "Please input " << arcNum << " arcs information!!" << endl;
for (int i = 0; i < arcNum; i++)
{
cout << "The arc " << i << " :"<<endl;
cout << "The arc tail:";
cin >> tail;
cout << "The arc head:";
cin >> head;
arc=new GraphArcNode(0,tail,head, graphNodeSet[tail].gettail(),graphNodeSet[head].gethead());
graphNodeSet[tail].settail(arc);
graphNodeSet[head].sethead(arc);
cout << "" << endl;
cout << "The graph now is:" << endl;
for (int i = 0; i < nodeNum; i++)
{
cout << "i=" << i << endl;
GraphArcNode* tail = graphNodeSet[i].gettail();
GraphArcNode* head = graphNodeSet[i].gethead();
while (tail != nullptr)
{
cout << "tail->getTailIndex()=" << tail->getTailIndex();
cout << " tail->getHeadIndex=" << tail->getHeadIndex() << endl;
tail = tail->getNextTailArcNode();
}
}
cout << "" << endl<< endl;
}
cout << "Complete the arcs information input!! " << endl;
}
int getGraphNodeNum()
{
return nodeNum;
}
GraphArcNode* getGraphNodeTail(int nodeIndex)
{
return graphNodeSet[nodeIndex].gettail();
}
GraphArcNode* getGraphNodeHead(int nodeIndex)
{
return graphNodeSet[nodeIndex].gethead();
}
};
int findNextReverseAdjNodeIndex(OLGraph g, int currentNodeIndex, vector<bool>& visited)
{
if (currentNodeIndex >= 0)
{
GraphArcNode* currentArcNode = g.getGraphNodeHead(currentNodeIndex);
while ((currentArcNode != nullptr) && (visited[currentArcNode->getTailIndex()]))
{
currentArcNode = currentArcNode->getNextHeadArcNode();
}
if (currentArcNode != nullptr)
{
return currentArcNode->getTailIndex();
}
else
{
return -1;
}
}
return -1;
}
void DFSSecond(OLGraph g, int nodeIndex, vector<bool>& visited)
{
visited[nodeIndex] = true;
for (int nextNodeIndex = findNextReverseAdjNodeIndex(g, nodeIndex, visited); nextNodeIndex >= 0; nextNodeIndex = findNextReverseAdjNodeIndex(g, nodeIndex, visited))
{
DFSSecond(g, nextNodeIndex, visited);
}
return;
}
void DFSTraverseSecond(OLGraph g, vector<int> finishedNode)
{
set<int> alreadyAdded;
vector<bool> visited(g.getGraphNodeNum(), false);
vector<vector<int>> connectedComponentArray;
vector<int> temp;
for (int i = g.getGraphNodeNum() - 1; i >= 0; i--)
{
temp = {};
if (!visited[finishedNode[i]])
{
DFSSecond(g, finishedNode[i], visited);
}
for (int j = 0; j < g.getGraphNodeNum(); j++)
{
if ((visited[j])&&(alreadyAdded.find(j)== alreadyAdded.end()))
{
temp.push_back(j);
alreadyAdded.insert(j);
}
}
if (temp.size() != 0)
{
connectedComponentArray.push_back(temp);
}
}
for (int i = 0; i < connectedComponentArray.size(); i++)
{
for (int j = 0; j < connectedComponentArray[i].size(); j++)
{
cout << connectedComponentArray[i][j] << " ";
}
cout << endl;
}
return;
}
int findNextAdjNodeIndex(OLGraph g, int currentNodeIndex, vector<bool>& visited)
{
if (currentNodeIndex >= 0)
{
GraphArcNode* currentArcNode = g.getGraphNodeTail(currentNodeIndex);
while ((currentArcNode != nullptr) && (visited[currentArcNode->getHeadIndex()]))
{
currentArcNode = currentArcNode->getNextTailArcNode();
}
if (currentArcNode != nullptr)
{
return currentArcNode->getHeadIndex();
}
else
{
return -1;
}
}
return -1;
}
void DFSFirst(OLGraph g, int nodeIndex, vector<bool>& visited, vector<int> &finishedNode, int &finishedNodeNum)
{
visited[nodeIndex] = true;
for (int nextNodeIndex = findNextAdjNodeIndex(g, nodeIndex, visited); nextNodeIndex >= 0; nextNodeIndex = findNextAdjNodeIndex(g, nodeIndex, visited))
{
DFSFirst(g, nextNodeIndex, visited, finishedNode, finishedNodeNum);
}
finishedNode[finishedNodeNum++] = nodeIndex;
return;
}
void DFSTraverseFirst(OLGraph g)
{
int finishedNodeNum = 0;
vector<int> finishedNode(g.getGraphNodeNum(),0);
vector<bool> visited(g.getGraphNodeNum(), false);
for (int i = 0; i < g.getGraphNodeNum(); i++)
{
if (!visited[i])
{
DFSFirst(g, i, visited, finishedNode, finishedNodeNum);
}
}
cout << "finishedNodeNum=" << finishedNodeNum << endl;
for (int i = 0; i < finishedNode.size(); i++)
{
cout << finishedNode[i] << endl;
}
DFSTraverseSecond(g, finishedNode);
return;
}
void printGraph(OLGraph g)
{
for (int i = 0; i < g.getGraphNodeNum(); i++)
{
cout << "i=" << i << endl;
GraphArcNode* tail =g.getGraphNodeTail(i);
GraphArcNode* head = g.getGraphNodeHead(i);
while (tail!=nullptr)
{
cout << "tail->getTailIndex()=" << tail->getTailIndex();
cout << "tail->getHeadIndex="<<tail->getHeadIndex() << endl;
tail = tail->getNextTailArcNode();
}
}
}
//测试程序
int main()
{
OLGraph g(4,7);
g.createGraph();
DFSTraverseFirst(g);
}