其他分享
首页 > 其他分享> > 有向无环图及其应用

有向无环图及其应用

作者:互联网

一.有向无环图(DAG图)

二.拓扑排序(AOV网,顶点表示活动)

1.说明

2.代码

void topologicalsort(Graph*g)
{
//创建一个count数组用来存储所有顶点的入度
    int*count=(int *)malloc(sizeof(int)*g->numv);
    for(int i=0;i<g->numv;i++)
    {
        count[i]=0;
    }
    Edge*p;
    //遍历邻接表,将所有点的入度进行存储
    for(int i=0;i<g->numv;i++)
    {
        p=g->NodeTable[i].adj;
        if(p!=NULL)
        {
            count[p->dest]++;
            p=p->link;
        }
    }
    //相当于入栈
    int top=-1;
    for(int i=0;i<g->numv;i++)
    {
        if(count[i]==0)
        {
            count[i]=top;//该点的count值等于上一个点的坐标值
            top=i;//top记录了点的下标
        }
    }
    int v,w;
    for(int i=0;i<g->numv;i++)//这层遍历主要是遍历栈中所有元素,而用count[]中的元素只会查找所有未入过栈的,因此count[i]可以等于0
    {
        if(top==-1)
        {
            printf("网络中有回路\n");
            return;
        }
        else
        {
            v=top;//找到栈顶元素的下标
            top=count[top];//找到栈中下一个元素下标,即count数组中该点前一个入度为0的数,将top重新赋值,相当于栈中的出栈操作
            printf("%c-->",g->NodeTable[v]);
            //广度遍历,在邻接表中查找所有与该点相连的点,在count数组中将他们的入度都减1
            w=getfirstneighbor(g,g->NodeTable[v].data);
            while(w!=-1)
            {
                count[w]--;
                if(count[w]==0)//只会检查所有未入过栈的,因此count中有些记录下标,有些记录入度不冲突
                {
                    count[w]=top;//将count[w]赋值为栈中下一个元素的坐标
                    top=w;//记录该点的坐标,便于以后输出
                }
                w=getnextneighbor(g,g->NodeTable[v].data,g->NodeTable[w].data);
            }
            
        }
    }
    
}

总结

三.关键路径(AOE网,顶点表示时间,边表示活动)

#define MAX_COST 0x7FFFFFFF
//初始化时,将存储边的矩阵上无边的点改为0
void CriticalPath(Grapg*g)
{
//创建存储点的最早开始时间和点的最晚开始时间的数组,并为其初始化
    int *ve=(int*)malloc(sizeof(int)*g->numv);
    int *vl=(int*)malloc(sizeof(int)*g->numv);
    for(int i=0;i<g->numv;i++)
    {
        ve[i]=0;
        vl[i]=MAX_COST;
    }
    int j,w;
    //求ve[]
    for(i=0;i<g->numv;i++)
    {
        j=getfirstneighbor(g,g->list[i]);
        while(j!=-1)//找到i的所有邻接点,并为邻接点的ve[]赋值
        {
            w=getweight(g,i,j);
            if(ve[i]+w>ve[j])//找到最大的值
            {
                ve[j]=ve[i]+w;
            }
            j=getnextneighbor(g,g->list[i],g->list[j]);
        }
    }
    //求vl[]
    int n=g->numv;
    //共有n个点,最后一个点的下标为n-1,故倒数第二个点的下标为n-2
    for(i=n-2;i>0;i--)
    {
        j=getfirstneighbor(g,g->list[i]);
        while(j!=-1)
        {
            w=getweight(g,i,j);
            if(vl[i]<vl[j]-w)//找到最小值
            {
                vl[i]=vl[j]-w;
            }
            j=getnextneighbor(g,g->list[i],g->list[j]);
        }
    }
    //求边的最早开始时间和边的最晚开始时间,判断是否相等后进行输出
    int Ae,Al;
    for(i=0;i<n;i++)
    {
        j=getfirstneighbor(g,g->list[i]);
        while(j!=-1)
        {
            int w=getweight(g,i,j);
            Ae=ve[i];
            Al=vl[j]-w;
            if(Ae==Al)
            {
                printf("<%c,%c>是关键路径\n",g->list[i],g->list[j]);
            }
            j=getnextneighbor(g,g->list[i],g->list[j]);
        }
    }
    free(ve);
    free(vl);
}

总结

四.最短路径(Dijkstra)

设置两个数组
int *dist=(int *)malloc(sizeof(int));
int *path=(int *)malloc(sizeof(int));
创建函数查找最短路径
void ShortestPath(Graph*g, char v,int dist[],int path[])
{
    int n=g->numv;
    bool*S=(bool*)malloc(sizeof(bool)*n);//记录是否被访问过
    int v=getvpos(g,v);//获得起始顶点的位置坐标
    for(int i=0;i<n;i++)
    {
        dist[i]=getweight(g,v,i);//更新起始点到所有点的路径权重
        S[i]=false;//初始化所有点都未被访问过
        if(i!=v&&dist[i]<MAX_COST)//初始化path函数,如果不是自身,并且到起始点有路径,就更新它们的起始点数组中的内容,否则就设为-1
        {
            path[i]=v;
        }
        else
        {
            path[i]=-1;
        }
    }
    S[v]=true;
    int min;
    for(i=0;i<n-1;i++)//除起始点外,所有点都被访问一遍
    {
        min=MAX_COST;
        int u=v;
        for(int j=0;j<n;j++)//找到未被访问的点中路径最短的点,遍历了dist[]
        {
            if(!S[j]&&dist[j]<min)//找到未被访问过的点的路径最小值
            {
                u=j;
                min=dist[j];
            }
        }
        //将点找到之后,更新数组中的数据
        S[u]=true;
        for(int k=0;k<n;k++)//循环所有未被访问过的点,更新u到他们的所有数据
        {
            w=getweight(g,u,k);//得到与u相连的所有点的路径
            if(!S[k]&&w<MAX_COST&&dist[u]+w<dist[k])//如果它未被访问过,并且有路径,并且从起点到k的路大于经过u到k的路,就重新为其赋值
            {
                dist[k]=dist[u]+w;
                path[k]=u;
            }
        }
    }
}

总结

标签:count,dist,ve,int,及其,入度,环图,应用,top
来源: https://blog.csdn.net/hieap/article/details/111441824