有向图的强连通分量

     以下内容主要参考了严蔚敏版的数据结构教材
     以下算法求有向图的每一个强连通分量中的节点并把一个强连通分量中的所有节点放在一个集合中。算法包含两次深度优先搜索过程:

  1. 第一次深度优先搜索过程按照从弧尾到弧头的顺序深度优先搜索并按照节点的所有邻接点是否都访问完成的先后顺序对访问的节点顺序进行排序。也就是说数组 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的元素的值是最先其所有邻接点都访问完成的节点的索引。
  2. 第二次深度优先搜索按照 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()创建的。
 
图1.
 
图2.
 
图3.
 
图4.
 
图5.
//图的十字链表表示
//弧节点
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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qqssss121dfd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值