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

 
十字链表表示特点
  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\n");
     scanf("%d",&G.vexnum);
     //printf("input arcnum of G\n");
     scanf("%d",&G.arcnum);
     printf("input value of each vertex of G\n");           // 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\n");
     for(k=0;k<G.arcnum;++k)
     {
          scanf("%c %c",&u,&v);          
          getchar();          //eat the \n
          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\t",G.xlist[i].data);
     printf("\n");
     for(i=0;i<G.vexnum;++i)
     {
          for(p=G.xlist[i].firstout;p!=NULL;p=p->tlink)
               printf("%c--->%c\t",G.xlist[i].data,G.xlist[p->headvex].data);
     }
     printf("\n");
}
 
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\n");
     scanf("%c %c",&u,&v);
     InsertArc(G,u,v);
     Display(G);
     printf("input to be deleted vertex:\n");
     getchar();
     scanf("%c",&u);
     DeleteVex(G,u);
     Display(G);
     printf("input to be deleted arc:\n");
     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
*/

转载于:https://www.cnblogs.com/pkg313133/p/3448833.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值