• 有向图的十字链表存储表示 以及相关操作(包括增加弧、删除弧、删除顶点等)


     
    十字链表表示特点
     1.针对弧结点,增加入弧链表结构和出弧链表结构;
    2.容易求得任意顶点的出度和入度,专用于有向图的操作;
    3.结构实现比较复杂。
     
     
    基本数据结构
     
    1.弧的数据结构
    typedef struct Arc
    {
         int tailvex;
         int headvex;
         struct OLGArc *hlink;
         struct OLGArc *tlink;
    }OLGArc;
     
    2.顶点结构
    typedef struct VexNode
    {
         char data;
         OLGArc *firstin;
         OLGArc *firstout;
    }OLGVNode;
     
    3.图的十字链表表示
    typedef struct
    {
         OLGVNode xlist[MAX_VERTEX_NUM];
         int vexnum;
         int arcnum;
    }OLGraph;
     
    有向图的十字链表表示的相关操作
     
    1.求图中某顶点在顶点数组中的下标
    int LocateVex(OLGraph G,char x)
    {
         int i;
         for(i=0;i<G.vexnum;++i)
              if(G.xlist[i].data==x)
                   return i;
              return -1;
    }
     
    2.创建有向图的十字链表存储表示
    void CreateOLGraph(OLGraph &G)
    {
         int i,j,k;
         char u,v;      //printf("input vexnum of G ");
         scanf("%d",&G.vexnum);
         //printf("input arcnum of G ");
         scanf("%d",&G.arcnum);
         printf("input value of each vertex of G ");           // initial vertex array
        getchar();
         for(i=0;i<G.vexnum;++i)
         {
              scanf("%c",&G.xlist[i].data);     //such as A B C D ,There is a blank between two vertex when you input data
              if(i!=G.vexnum - 1)
                   getchar();              //eat the blank
              G.xlist[i].firstin=NULL;
              G.xlist[i].firstout=NULL;
         }
         printf("input the information of arc of G ");
         for(k=0;k<G.arcnum;++k)
         {
              scanf("%c %c",&u,&v);          
              getchar();          //eat the
              i=LocateVex(G,u);
              j=LocateVex(G,v);
              OLGArc *p;
              p=(OLGArc*)malloc(sizeof(OLGArc));   // apply a new save space
              p->tailvex=i;
              p->headvex=j;
              p->hlink=G.xlist[j].firstin;
              p->tlink=G.xlist[i].firstout;
              G.xlist[i].firstout=p;
              G.xlist[j].firstin=p;
         }
    }
     
    3.十字链表存储表示的有向图的打印输出
    void Display(OLGraph G)
    {
         int i,j,k;
         OLGArc *p;
         for(i=0;i<G.vexnum;++i)
                   printf("%c ",G.xlist[i].data);
         printf(" ");
         for(i=0;i<G.vexnum;++i)
         {
              for(p=G.xlist[i].firstout;p!=NULL;p=p->tlink)
                   printf("%c--->%c ",G.xlist[i].data,G.xlist[p->headvex].data);
         }
         printf(" ");
    }
     
    4.在有向图中插入一条新的弧
    void InsertArc(OLGraph &G,char u,char v)
    {
         int i,j;
         OLGArc *p;
         i=LocateVex(G,u);
         j=LocateVex(G,v);
         p=(OLGArc*)malloc(sizeof(OLGArc));
         p->headvex=j;
         p->tailvex=i;
         p->hlink=G.xlist[j].firstin;
         p->tlink=G.xlist[i].firstout;
         G.xlist[i].firstout=p;
         G.xlist[j].firstin=p;
         G.arcnum++;
    }
     
    5.在有向图中删除一条弧
    void DeleteArc(OLGraph &G,char u,char v)
    {
         int i,j;
         OLGArc *p,*q;
         i=LocateVex(G,u);
         j=LocateVex(G,v);
         //修改u的出弧链表
         if(G.xlist[i].firstout->headvex==j)
         {
              q=G.xlist[i].firstout;
              G.xlist[i].firstout=q->tlink;
              G.arcnum--;
         }
         else
         {
              for(p=G.xlist[i].firstout;p&&(p->tlink!=NULL)&&(p->tlink->headvex!=j);p=p->tlink);
                        if(p&&p->tlink)       //之前没有加p->tlink!=NULL,若p->tlink==NULL,则q==NULL,q->tlink也就无意义了,同上差不多,会造成各种指针错误
                        {
                             q=p->tlink;
                             p->tlink=q->tlink;
                             G.arcnum--;
                        }
         }
         //修改v的入弧链表
         if(G.xlist[j].firstin->tailvex==i)
         {
              q=G.xlist[j].firstin;
              G.xlist[j].firstin=q->hlink;
                free(q);
         }
         else
         {
              for(p=G.xlist[j].firstin;p&&(p->hlink)&&(p->hlink->tailvex!=i);p=p->hlink);
              if(p&&p->hlink)
              {
                 q=p->hlink;
                 p->hlink=q->hlink;
                 free(q);
              }
         }
    }
    6.删除有向图中的一个顶点
    顶点删除分两步删除与v相关的弧
    首先删除顶点v的所有入弧,这些弧结点分散于其他顶点的出弧链表中,同时也构成了顶点v的入弧链表。
    在删除顶点v的入弧结点时不用维护顶点v入弧链表的连通性,但要维护该弧结点所在的其他顶点出弧链表的连通性。
    void DeleteVex(OLGraph &G,char v)
    {
         int k=LocateVex(G,v);
         int i,j;
         OLGArc* p=NULL;
         OLGArc* q=NULL;
         for(j=0;j<G.vexnum;j++)   //遍历所有结点的出弧链表,找到待删的弧结点(以v作为弧头结点的弧的结点),修改每个结点的要修改处的指针,保持目标结点被删除后仍保持原有的连通性
         {
              if(G.xlist[j].firstout==NULL)  //该顶点没有出弧链表
                   continue;
              else
              {
                   if(G.xlist[j].firstout->headvex==k)    //出弧链表的第一个结点恰好是要删除的结点
                   {
                        q=G.xlist[j].firstout;
                        G.xlist[j].firstout=q->tlink;
                        G.arcnum--;
                   }
                   else
                   {   //遍历链表找到要删除的弧的结点,其中(p->tlink!=NULL),之前没有加上,造成潜在隐患,若p->tlink==NULL,则p->tlink->headvex无效的引用
                        for(p=G.xlist[j].firstout;p&&(p->tlink!=NULL)&&(p->tlink->headvex!=k);p=p->tlink);
                        if(p&&p->tlink)       //之前没有加p->tlink!=NULL,若p->tlink==NULL,则q==NULL,q->tlink也就无意义了,同上差不多,会造成各种指针错误
                        {
                             q=p->tlink;
                             p->tlink=q->tlink;
                             G.arcnum--;
                        }
                   }
              }
         }
      //删除v的出弧链表和入弧链表
       p=G.xlist[k].firstout;
       while(p)
       {
            q=p;
            p=p->tlink;
            free(q);
       }
         p=G.xlist[k].firstin;
       while(p)
       {
            q=p;
            p=p->hlink;
            free(q);
       }
       for(j=k+1;j<G.vexnum;j++)   //数组前移
            G.xlist[j-1]=G.xlist[j];
       G.vexnum--;    //顶点数减一
       for(j=0;j<G.vexnum;j++)
         {
              for(p=G.xlist[j].firstout;p;p=p->tlink)
              {
                   if(p->tailvex>k)
                        p->tailvex--;
                   if(p->headvex>k)
                        p->headvex--;
              }
         }
    }
     
    7.主函数
    int main()
    {
         OLGraph G;
         char u,v;
         CreateOLGraph(G);
         Display(G);
         printf("input newly inserted arc ");
         scanf("%c %c",&u,&v);
         InsertArc(G,u,v);
         Display(G);
         printf("input to be deleted vertex: ");
         getchar();
         scanf("%c",&u);
         DeleteVex(G,u);
         Display(G);
         printf("input to be deleted arc: ");
         getchar();
        scanf("%c %c",&u,&v);
         DeleteArc(G,u,v);
         Display(G);
         return 0;
    }
    //测试数据(创建有向图的十字链表)(测试数据对应于本文第一幅图)
    /*
    4
    7
    A B C D
    A B
    A C
    C A
    C D
    D A
    D B
    D C
    */
  • 相关阅读:
    linux curses函数库
    在Android library中不能使用switch-case语句访问资源ID的原因分析及解决方案
    Android Support ;v4、v7、v13的区别
    background-position
    java web 之 web.xml篇
    javaweb之Cookie篇
    Enumeration 接口
    Java Bad version number in .class file
    使用AppCan自带的升级功能实现移动端升级
    obj.offsetHeight与obj.style.height区别
  • 原文地址:https://www.cnblogs.com/pkg313133/p/3448833.html
Copyright © 2020-2023  润新知