图--拓扑排序

拓扑排序(Topological Sorting):一种对有向无环图(DAG)的所有顶点进行线性排序的方法,使得图中任意一点 u 和 v,如果存在有向边<u,v>,则 u 必须在 v 之前出现。对有向图进行拓扑排序产生的线性序列称为满足拓扑次序的序列,简称拓扑排序。

图的拓扑排序是针对有向无环图来说的,无向图和有向有环图不存在拓扑排序。

针对以上有向无环图,1→2→3→4→5是该图的一个拓扑序列,1→3→2→4→5也是该图的拓扑序列。1→2→4→3→5不是该图的拓扑序列,因为4依赖于3.对于一个有向无环图来说,拓扑序列可能不止一个。

拓扑排序有两种实现方法,分别是Kahn算法和DFS深度优先搜索算法。

Kahn算法

kahn算法采用入度方法,其算法过程如下:

  1. 选择一个入度为0的节点(表示该节点不依赖其他节点),输出到结果序列中;
  2. 删除该节点以及该节点的边;
  3. 重复执行步骤1和2,直到所有节点输出到结果序列中,完成拓扑排序;
  4. 如果最后存在入度不为0的节点,说明有向图中存在环,无法进行拓扑排序。

重复以上步骤即可

为了实现这个算法,使用邻接表来表示有向图,并且需要一个数组来存储每个结点的入度(指向该结点的结点数量),如果为 0 则说明该结点没有结点指向它。遍历所有节点,将入度为0的点即节点1入栈

弹出栈顶元素即节点1并输出,然后遍历节点1的邻接节点(节点2,3),将它们的入度减1,如果入度为0则入栈,重复此操作,直到栈为空,算法结束。

#include <bits/stdc++.h>
using namespace std;
#define MAXVERTIES 20
#define OK 1
#define ERROR 0

int indegree[MAXVERTIES] = { 0 };    //用于存储入度信息


//定义结点
struct VexNode {
    int data;
    VexNode *next;
};

//定义弧
struct ArcNode {
    int data;
    VexNode *firstacr = NULL;
};

//定义邻接表
struct GraphList {
    ArcNode arclist[MAXVERTIES];
    int vexnum, arcnum;
};

//定义栈
struct Stack {
    int Sacklist[MAXVERTIES] = { 0 };
    int top = -1;
};

//入栈操作
void Push(Stack &S, int key) {
    if (S.top == MAXVERTIES) {
        cout << "栈已满!" << endl;
        return;
    }
    S.top++;
    S.Sacklist[S.top] = key;
}

//出栈操作
int Pop(Stack &S) {
    if (S.top == -1) {
        cout << "栈为空!" << endl;
        return -1;
    }
    int temp = S.Sacklist[S.top];
    S.top--;
    return temp;
}

//返回结点在结点数组中的下标
int Location(GraphList &G, int key) {
    for (int i = 0; i < G.vexnum; i++) {
        if (G.arclist[i].data == key) {
            return i;
        }
    }
    return -1;
}

//创建图
void CreatGraph(GraphList &G) {
    cout << "请输入顶点数:" << endl;
    cin >> G.vexnum;
    cout << "请输入顶点信息:" << endl;
    for (int i = 0; i < G.vexnum; i++) {
        cin >> G.arclist[i].data;
    }
    cout << "请输入弧数:" << endl;
    cin >> G.arcnum;
    cout << "请输入弧端点信息:" << endl;
    for (int i = 0; i < G.arcnum; i++) {
        int v1, v2;
        cin >> v1 >> v2;
        int Location1 = Location(G, v1);
        int Location2 = Location(G, v2);
        VexNode *new_node = new VexNode;
        new_node->data = Location2;
        new_node->next = G.arclist[Location1].firstacr;
        G.arclist[Location1].firstacr = new_node;
        indegree[Location2]++;
    }
}

//拓扑排序
int TopoSort(GraphList &G, int *topolist) {
    Stack S;
    int topo = 0;
    //先将所有入度为0的结点入栈
    for (int i = 0; i < G.vexnum; i++) {
        if (indegree[i] == 0) {
            Push(S, i);
        }
    }
    //依次出栈入度为0的结点
    while (S.top != -1) {
        int vx = Pop(S);
        topolist[topo++] = G.arclist[vx].data;    //输出结点
        VexNode *temp = G.arclist[vx].firstacr;
        //删除以该结点为尾的弧
        while (temp != NULL) {
            int index = temp->data;
            indegree[index]--;    //将该弧的弧头结点入度减1
            //如果入度为0,则入栈
            if (indegree[index] == 0) {
                Push(S, index);
            }
            temp = temp->next;
        }
    }
    topolist[topo] = -1;
    //如果拓扑序列中的元素个数等于所有元素个数,则该图无环,否则该图有环
    if (topo == G.vexnum) {
        return OK;
    } else {
        return ERROR;
    }
}

int main() {
    GraphList GL;
    CreatGraph(GL);
    int topolist[MAXVERTIES] = { 0 };
    int vx = TopoSort(GL, topolist);
    if (!vx) {
        cout << "有环!" << endl;
    } else {
        cout << "有向无环!" << endl;
        cout << "拓扑序列如下:" << endl;
        for (int i = 0; topolist[i] != -1; i++) {
            cout << topolist[i] << " ";
        }
    }
    return 0;
}

DFS

DFS算法采用出度算法,其算法过程如下:

  1. 对有向图进行深度优先搜索;
  2. 在执行深度优先搜索时,若某个顶点不能继续前进,即顶点的出度为0,则将此顶点入栈。
  3. 最后对栈中的序列进行逆排序,即完成拓扑排序;如果深度优先搜索时,碰到已遍历的节点,说明存在环。

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值