数据结构3-拓扑排序

来源:互联网 发布:汉仪菱心简体mac版 编辑:程序博客网 时间:2024/06/08 18:09

1.拓扑排序的理解

        拓扑排序是用于有向无环图里,将优先的节点先输出的一种排序方式。有向是指节点与节点之间有一个优先关系,例如想烧一壶水,那么必须先用水壶去接水,再用水壶去烧水,其中接水就是烧水的优先动作,想烧水就必须先接水。无环是指一系列的动作中必须是有一个入口和一个出口的,举一个有环的例子,先有鸡还是先有蛋,鸡要蛋孵,蛋要鸡下(不从科学角度考虑,例子的设定就是这样),这个例子中就出现了有环的现象,鸡和蛋之前互为优先关系,有环的图是无法进行拓扑排序的。


2.偏序和全序

        只要是满足了有向、无环的图就满足偏序关系。那么如果要满足全序就得多加一个条件,有向、无环图中任意两顶点之间还需要有明确的关系。先说一个偏序的例子,小明有买菜和炒菜两件事要做,买菜的顺序是先到菜市场,再买菜,最后回家;炒菜的顺序是先到冰箱拿菜出来,再洗菜,最后炒菜。在这两件事情中不分先后,那么就可能会出现两种情况,先买菜后炒菜或者先炒菜后买菜,这就是偏序。如果是全序的情况下这个例子就会增加一个新的条件,小明的冰箱里没有菜了,他需要先去买菜之后才可以炒菜,这样出现的情况就只有一种情况,这就是全序。


3.算法思路

(1)找到一个没有后继的定点存放到栈中(得到一个倒序的顺序)

(2)从图中删除该定点和它的弧(与其他定点的关系)

(3)出栈(得到正序的拓扑排序结果)


4.代码

/*拓扑排序算法*//// <summary>/// 寻找没有后继点的节点(出度为0)/// 邻接矩阵的一行全为0/// </summary>/// <returns></returns>private int FindNoSuccessor(){    bool isEdge;    for (int i = 0; i < numVert; i++)       //numVert是图中的顶点数    {        isEdge = false;        for (int j = 0; j < numVert; j++)        {            if (adjmatrix[i, j] != 0)            {                isEdge = true;                break;            }        }        if (!isEdge)            return i;    }    return -1;}/// <summary>/// 从顶点数组中删除点/// 从临接矩阵中删除点/// </summary>/// <param name="vert"></param>private void DelVertex(int vert){    if (vert <= numVert - 1)    {        //从顶点数组中删除点        for (int i = vert; i < numVert; i++)        {            vertices[i] = vertices[i + 1];    //vertices是用于存储图的数组        }        //从临接矩阵中删除点        //删除行        for (int i = vert; i < numVert; i++)        {            MoveRow(i, numVert);        }        //删除列        for (int i = vert; i < numVert; i++)        {            MoveCol(i, numVert - 1);        }        numVert--;    }}/// <summary>/// 移动临接矩阵中的行/// </summary>/// <param name="row"></param>/// <param name="lenth"></param>private void MoveRow(int row, int lenth){    for (int col = row; col < lenth; col++)    {        adjmatrix[row, col] = adjmatrix[row + 1, col];  //adjmatrix是用于存放定点间关系的矩阵(临接矩阵)    }}/// <summary>/// 移动列/// </summary>/// <param name="col"></param>/// <param name="lenth"></param>private void MoveCol(int col, int lenth){    for (int row = col; row < lenth; row++)    {        adjmatrix[row, col] = adjmatrix[row, col + 1];    }}/// <summary>/// 拓扑排序/// 将出度为0的节点入栈,这样就可以把拓扑排序的顺序从后往前保存起来,/// 再从栈里取出,顺序就是从前往后的。/// </summary>public void TopSort(){    int origVerts = numVert;    //存放返回节点的栈    System.Collections.Stack result = new Stack();    while (numVert > 0)    {        //找到第一个没有后继节点的节点        int currVertex = FindNoSuccessor();        if (currVertex == -1)        {            Console.WriteLine("图为环路图,不能搞拓扑排序");            return;        }        //如果找到,将其加入返回结果栈        result.Push(vertices[currVertex].Data);        //然后删除此节点        DelVertex(currVertex);    }    /*输出排序后的结果*/    Console.Write("拓扑排序的顺序为:");    while (result.Count > 0)    {        Console.Write(result.Pop() + " ");    }    Console.WriteLine();}


原创粉丝点击