邻接表拓扑排序算法
算法思想:
- 初始化一个栈
s
。 - 遍历图中的每个顶点,如果顶点的入度为 0,则将其压入栈
s
。 - 初始化一个计数器
count
为 0,用于记录输出的顶点数量。 - 当栈
s
非空时,重复以下步骤:- 从栈
s
弹出一个顶点i
。 - 输出顶点
i
,并将其存储在数组print
的count
位置,同时将计数器count
加 1。 - 遍历顶点
i
的邻接顶点v
:- 将顶点
v
的入度减 1。 - 如果顶点
v
的入度变为 0,则将其压入栈s
。
- 将顶点
- 从栈
- 判断输出的顶点数量
count
是否小于图中的顶点数量G.vexnum
:- 如果小于,则说明图中存在环,返回
false
。 - 如果相等,则拓扑排序成功,返回
true
。
- 如果小于,则说明图中存在环,返回
根据算法的思想,通过不断移除入度为 0 的顶点,保证了在拓扑序列中,每个顶点都在它的依赖顶点之后。
代码
bool topologicalsort(graph G){
initstack(s); // 初始化栈 s
for (int i = 0; i < G.vex.num; i++) {
if (indegree[i] == 0)
push(s, i); // 将入度为 0 的顶点压入栈 s
}
int count = 0; // 计数器,用于记录输出的顶点数量
while (!isempty(s)) {
pop(s, i); // 从栈 s 中弹出一个顶点 i
print[count++] = i; // 将弹出的顶点 i 输出,并计数器加 1
for (p = G.vertices[i].firstarc; p; p = p.nextarc) {
v = p.adjvex;
if (!(--indegree[v]))
push(s, v); // 对于顶点 i 的邻接顶点 v,将其入度减 1,如果入度变为 0,则将其压入栈 s
}
}
if (count < G.vexnum)
return false; // 输出的顶点数量小于图中的顶点数量,说明图中存在环
else
return true; // 拓扑排序成功
}
完整代码
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
struct ArcNode {
int adjvex;
struct ArcNode* nextarc;
};
struct VNode {
struct ArcNode* firstarc;
// 可以根据需要添加其他属性
};
struct Graph {
int vexnum;
vector<VNode> vertices;
vector<int> indegree;
};
void initstack(stack<int>& s) {
while (!s.empty()) {
s.pop();
}
}
void push(stack<int>& s, int item) {
s.push(item);
}
void pop(stack<int>& s, int& item) {
item = s.top();
s.pop();
}
bool isempty(stack<int>& s) {
return s.empty();
}
bool topologicalSort(Graph G) {
stack<int> s;
initstack(s);
for (int i = 0; i < G.vexnum; i++) {
if (G.indegree[i] == 0)
push(s, i);
}
int count = 0;
int print[G.vexnum];
while (!isempty(s)) {
int i;
pop(s, i);
print[count++] = i;
ArcNode* p;
for (p = G.vertices[i].firstarc; p != NULL; p = p->nextarc) {
int v = p->adjvex;
if (!(--G.indegree[v]))
push(s, v);
}
}
if (count < G.vexnum)
return false;
else {
cout << "拓扑排序结果为:";
for (int i = 0; i < count; i++) {
cout << print[i] << " ";
}
cout << endl;
return true;
}
}
int main() {
// 创建一个具体的图作为示例
Graph G;
G.vexnum = 6; // 顶点数量
G.vertices.resize(G.vexnum);
G.indegree.resize(G.vexnum);
// 初始化顶点的链表和入度
for (int i = 0; i < G.vexnum; i++) {
G.vertices[i].firstarc = NULL;
G.indegree[i] = 0;
}
// 添加有向边
// 0 -> 1 -> 3
// \-> 2 -> 3
// \-> 4 -> 5
G.vertices[0].firstarc = new ArcNode{1, NULL};
G.vertices[0].firstarc->nextarc = new ArcNode{2, NULL};
G.vertices[0].firstarc->nextarc->nextarc = new ArcNode{4, NULL};
G.vertices[1].firstarc = new ArcNode{3, NULL};
//G.vertices[1].firstarc = new ArcNode{0, NULL};
G.vertices[2].firstarc = new ArcNode{3, NULL};
G.vertices[4].firstarc = new ArcNode{5, NULL};
G.indegree[1] = 1;
G.indegree[2] = 1;
G.indegree[3] = 2;
G.indegree[4] = 1;
G.indegree[5] = 1;
bool success = topologicalSort(G);
if (!success) {
cout << "拓扑排序失败,图中存在环。" << endl;
}
return 0;
}