拓扑排序学习总结

a.简介:
拓扑排序主要用来解决满足一个给定图的各个结点的顺序问题。因此如何从实际问题中抽象出图是解决问题的关键。

b.主要步骤:

1.选择当前入度为0的节点,去除;
2.删除以上一节点为头的约束边;
3.递归以上两步直到删除图中所有节点。

c.注意事项:
1.清晰题中所描述的问题是否满足拓扑排序的要求;
2.将题中的事物(人,城市等)抽象成点,事物之间的关系抽象成边;
3.构建图:判断使用拓扑还是反拓扑,应结合题意,一般正向约束条件较多或无法判断开始的多个0入度点时;(具体问题之中边为有向边)
4.存图:选择合适的方式存图,节点少时用邻接矩阵,多时用邻接表存图时要注意两种方式的区别:邻接矩阵需要考虑多重边对入度的影响,而邻接表则不用;
5.判断题意是否涉及死环问题:死环判定条件:若排序后删除的节点数不等于所给图的节点数,则必存在环;
6.如果题中提到集合(许多元素具有同一性质)的问题:考虑并查集和并元素,如:两个人成绩相同,一个班级等;
7.常用方法:拓扑常用邻接表,队列,邻接矩阵,栈等数据结构相互结合存储,实际情况中要灵活运用。


代码如下:

邻接矩阵:

void topo(int n)//n个节点的图 
{
    for(int i=1;i<=n;++i)//循环加入n个节点 
    {
        int k;//记录所选点标号 
        for(int j=1;j<=n;++j)//选择入度为0的节点 
        {
            if(!ideg[j])
            {
                k=j; break;
            }
         } 
         ord[i]=k; ideg[k]=-1;//去除此点 
         for(int j=1;j<=n;++j)//去除所有关联边 
         {
            if(ideg[j]>0&&map[k][j])
            {
                --ideg[j];
            }
         }
    }
 } 

邻接矩阵+队列(可用优先队列)

void topo(int n)
{
    queue<int> que; stack<int> sta;
    for(int i=1;i<=n;++i)
    {
        if(!ideg[i])
        {
            que.push(i); ideg[i]=-1;
        }
    }
    while(!que.empty())
    {
        int now=que.front(); que.pop();
        sta.push(now);//只是举个例子 可用数组 
        for(int i=1;i<=n;++i)
        {
            if(map[now][i]&&ideg[i]>0)
            {
                 --ideg[i];
                if(!ideg[i])//此处应注意是now的邻接点 
                {
                  que.push(i); ideg[i]=-1;
                }
            } 
         } 
    }
}

邻接表+优先队列:

void topo(int n)
{
    queue<int,vector<int>,greater<int> > que;
    for(int i=1;i<=n;++i)
    {
        if(!ideg[i])//入队即标记 
        {
            que.push(i); ideg[i]=-1;
        }
    }
    cnt=0;
    while(!que.empty())
    {
        int now=que.top(); que.pop();//去除节点 
        ord[++cnt]=now;//保存序列 
        for(int i=head[now];i!=-1;i=edge[i].next)
        {
            int go=edge[i].to;//区分go与i 
            if(ideg[go]>0)  --idge[go];
            if(!idge[go])//入队即标记 一个点不能两次入队 
            {
                que.push(go); idge[go]=-1;
            }
         } 
    }
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值