数据结构3-拓扑排序

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();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值