您的位置:首页 > 其它

拓补排序

2014-10-07 15:23 78 查看
简单粗暴的开始

拓补排序实际上是图的深度优先搜索的一种拓展。

拓补排序一般针对的是有向无环图,(其实只有当实际问题中存在一个抽象的有向无环图时,我们有时候才需要一个拓补排序来解决某些问题)

拓补排序最后的序列可以保证,在这个序列中,所有的边都是从序列中前面的结点出发,到达序列中考后的点的。换一句话说,图中所有有向边的起点都是在终点的前面。来,画个图应该就可以秒懂了。



这实际上也是一个深度优先搜索的示例。当一个结点第一次被搜索时,标记为灰色,数字表示的是 [开始时间/结束时间],结束时间是指该结点没有可达结点或者所有直接可达结点都已经遍历过了(必须是黑色,若是灰色则证明存在环)
那么,此图中,按照结束时间的从大到小顺序即为A,B,E,D,C,F.次序列就为此图的拓补排序序列。
接下来就是代码了。

int topologicalSort(int** graph, int numV, int origin, int* pointColor, int* tpArray)
{

int tpIndex = numV-1;
std::stack<status> st;
status sOrigin;
sOrigin.v = origin;
sOrigin.index = 0;
st.push(sOrigin);
while (!st.empty())
{
status sV = st.top();
st.pop();
int i;
for (i = sV.index; i < numV; i++)
{
if (graph[sV.v][i])
{
if (pointColor[i] == WHITE)
{
sV.index = i + 1;
status detectedV;
detectedV.v = i;
detectedV.index = 0;
st.push(sV);
st.push(detectedV);
pointColor[i] = GRAY;
break;
}
else if (pointColor[i] == GRAY)
return -1;
}
}
if (i == numV)
{
pointColor[sV.v] = BLACK;
tpArray[tpIndex--] = sV.v;
}

}

return 0;
}

由于我应用的是非递归的深度优先搜索,所以定义了一个保存状态的结构体

struct status
{
int v;
int index;
};v是当前遍历的结点,index表示从V点出发,已经检测到了第index个结点是否可达。
graph是图的邻接矩阵表示的图,numV是结点总数,origin是起点。这里需要说明的是,完整的拓补排序对起点没有要求,这里我有点特殊化了,这段代码要求指明起点,而且起点可达所有图中其他结点,会这么写也是一道题的具体需要,当然思想是相同的。

pointColor是结点的着色情况数组,tpArray为排列好的拓步序列。

所有的都和深度遍历很相似,不同的是遇见GRAY的结点,说明图中有环,所有需要结束排序。

每当 i == numV时,说明当前探测的结点sV.v已经探测结束了,标记为黑色。

我们知道,拓补排序是按结束时间大小排列,也就是说,最先结束的结点应该排在序列最后面。所以我们从数组的最后一个位置开始往前排,没遇到个黑色结点,就往前进1.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c 拓补排序