您的位置:首页 > 理论基础 > 数据结构算法

图的邻接表存储和基本操作

2015-06-01 11:03 465 查看
书本当然是严奶奶的那本《数据结构(C语言版)》

参考代码:《数据结构》算法实现及解析(高一凡)

本文主要还是对这两位大神的东西整理一下,其实哈哈,还是代码的搬运工(逃)

/*****************图的邻接表存储表示*********************

******************制作人:Guosam'*************************

*****************时间:2015/5/22************************/

#define MAX_VERTEX_NUM 20

typedef enum GraphKind{DG,DN,UDG,UDN}GraphKind; //{有向图,有向网,无向图,无向网}

typedef struct ArcNode

{

    int adjvex;        //    该弧所指向的顶点的位置

    ArcNode *nextarc;    //指向下一条弧的指针

    InfoType *info;    //    网的权值指针

}ArcNode;    //表结点

typedef struct VNode

{

    VertexType data;        //顶点信息

    ArcNode *firstarc;        //指向第一条依附该顶点的弧的指针

}VNode,AdjList[MAX_VERTEX_NUM];

typedef struct

{

    AdjList vertices;

    int vexnum,arcnum;        //图的当前顶点数和弧数

    int kind;        //图的种类标志

}ALGraph;

/*****************图的邻接表存储表示的基本操作*********************

******************制作人:Guosam*************************

*****************时间:2015/5/22************************/

//若G中存在顶点u,则返回该顶点在图中的位置

int LocateVex(ALGraph G,VertexType u)

{

    int i;

    for(i=0;i<G.vexnum;++i)

        if(strcmp(u,G,vertices[i].data)==0)

            return i;

    return -1;

}

//采用邻接表存储结构,构造没有相关信息图或网G(用一个函数构造4种图)

void CreateGraph(ALGraph &G)

{

    int i,j,k,w; //w是权值

    VertexType va,vb;    //链接边或者弧的两个顶点

    ElemType e;

    printf("请输入图G的类型(有向图:0,有向网:1,无向图:2,无向图:3)");

    scanf("%d",&G.kind);

    printf("请输入图的顶点数,边数:");

    scanf("%d,%d",&G.vexnum,&G.arcnum);

    printf("请输入%d个顶点的值(<%d个字符):\n",G.vexnum,MAX_NAME);

    for(i=0;i<G.vexnum;++i)        //构造顶点向量

    {

        scanf("%s",G.vertices[i].data);

        G.vertices[i].firstarc==NULL;        //初始化与该顶点有关的出弧链表

    }

    if(G.kind%2)  //网

        printf("请输入每条弧(边)的权值、弧尾和弧头(以空格为间隔):\n");

    else //图

        printf("请输入每条弧(边)弧尾和弧头(以空格为间隔):\n");

    for(k=0;k<G.arcnum;++k)  //构造相关弧链表

    {

        if(G.kind%2)    //网

            scanf("%d%s%s",&w,va,vb);

        else  //图

            scanf("%s%s",va,vb);

        i=LocateVex(G.va);    //弧尾

        j=LocateVex(G,vb);    //弧头

        e.info=NULL;    //给待插表结点e赋值,图无权

        e.adjvex=j;        //弧头

        if(G.kind%2) //网

        {

            e.info=(int *)malloc(sizeof(int));        //动态生成存放权值的空间

            *(e.info)=w;

        }

        ListInsert(G.vertices[i].firstarc,1,e);        //插在第i个元素(出弧)的表头

        if(G.kind>=2)    //无向图或网,产生第二个表结点,并插在第j个元素(入弧)的表头

        {

            e.adjvex=i;    //e.info不变,不必再赋值

            ListInsert(G.vertices[j].firstarc,1,e);        //插在第j个元素的表头

        }

    }

}

//采用邻接表存储结构,由文件构造没有相关信息图或网G(用一个函数构造4种图)

void CreateGraphF(ALGraph &G)

{

    int i,j,k,w;  //w是权值

    VertexType va,vb;    //连接边或者弧的2个顶点

    ElemType e;

    char filename[13];

    FILE *graphlist;

    printf("请输入数据文件名()");

    scanf("%s",filename);

    printf("请输入图G的类型(有向图:0,有向网:1,无向图:2,无向图:3)");

    scanf("%d",&G.kind);

    graphlist=fopen(filename,"r");        //以读的方式打开数据文件,并以graphlist表示

    fscanf(graphlist,"%d",&G.vexnum);

    fscanf(graphlist,"%d",&G.arcsnum);

    for(i=0;i<G.vexnum;++i)        //构造顶点向量

    {

        scanf("%s",G.vertices[i].data);

        G.vertices[i].firstarc==NULL;        //初始化与该顶点有关的出弧链表

    }

    if(G.kind%2)  //网

        printf("请输入每条弧(边)的权值、弧尾和弧头(以空格为间隔):\n");

    else //图

        printf("请输入每条弧(边)弧尾和弧头(以空格为间隔):\n");

    for(k=0;k<G.arcnum;++k)  //构造相关弧链表

    {

        if(G.kind%2)    //网

            scanf("%d%s%s",&w,va,vb);

        else  //图

            scanf("%s%s",va,vb);

        i=LocateVex(G.va);    //弧尾

        j=LocateVex(G,vb);    //弧头

        e.info=NULL;    //给待插表结点e赋值,图无权

        e.adjvex=j;        //弧头

        if(G.kind%2) //网

        {

            e.info=(int *)malloc(sizeof(int));        //动态生成存放权值的空间

            *(e.info)=w;

        }

        ListInsert(G.vertices[i].firstarc,1,e);        //插在第i个元素(出弧)的表头

        if(G.kind>=2)    //无向图或网,产生第二个表结点,并插在第j个元素(入弧)的表头

        {

            e.adjvex=i;    //e.info不变,不必再赋值

            ListInsert(G.vertices[j].firstarc,1,e);        //插在第j个元素的表头

        }

    }

    fclose(graphlist);        //关闭数据文件

}

//销毁图G

void DestroyGraph(ALGraph &G)

{

    int i;

    ELemType e;

    for(i=0;i<G.vexnum:++i)    //对于所有的顶点

        if(G.kind%2)

            while(G.vertices[i].firstarc)        //对应的弧或者边链表不空

            {

                ListDelete(G.vertices[i].firstarc,1,e);

                if(e.adjvex>i)    //顶点序号>i(保证动态生成的权值空间只释放1次)

                 
4000
   free(e.info);

            }

        else //图

            DestroyList(G.vertices[i].firstarc);    //销毁弧或者边链表

    G.vexnum=0;        //顶点数为0

    G.arcsnum=0;    //边或者弧数为0

}

//返回v的值

VertexType&    GetVex(ALGraph G,int v)

{

    if(v>G.vexnum||v<0)

        exit (ERROR);

    return G.vertices[v].data;

}

//对v赋新值

Status PutVex(ALGraph &G,VertexType v,VertexType value)

{

    int i;

    i=LocateVex(G,v);

    if(i>-1)

    {

        strcpy(G.vertices[i].data,value);

        return OK;

    }

    return ERROR;

}

//返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1

int FirstAdjVex(ALGraph G,VertexType v)

{

    ArcNode *p;

    int v1;

    v1=LocateVex(G,v);    //v1为顶点v在图G中的序号

    p=G.vertices[v1].firstarc;

    if(p)

        return p->data.adjvex;

    else

        return -1;

}

//DeleteArc()、DeleteVex()和NextAdjVex()要调用的比较函数

Status equalvex(ElemType a,ELemType b)

{

    if(a.adjvex==b.adjvex)

        return OK;

    else

        return ERROR;

}

//v是G的某个顶点,w是v的邻接顶点,返回v的下一个邻接顶点的序号

int NextAdjVex(ALGraph G,VertexType v,VertexType w)

{

    LinkList p,p1;        //p1在Point()中用作辅助指针,Point函数是之前单链表中用的

    ElemType e;

    int v1;

    v1=LocateVex(G,v);    //v1为顶点v在图G中的序号

    e.adjvex=LocateVex(G,w);    //e.adjvex为顶点w在图G中的序号

    p=Point(G.vertices[v1].firstarc,e,equalvex,p1);        //p指向顶点v的链表中邻接顶点为w的结点

    if(!p||!p->next)    //    没找到w或者w是最后一个邻接点

        return -1;

    else  //p->data.adjvex==w

        return p->next->data.adjvex;    

}

//在图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做)

void InsertVex(ALGraph &G,VertexType v)

{

    strcpy(G.vertices[G.vexnum].data,v);    //构造新的顶点向量

    G.vertices[G.vexnum].firstarc=NULL;

    G.vexnum++;        //图G的顶点数加1

}

//删除G中顶点v及其相关的弧

Status DeleteVex(ALGraph &G,VertexType v)

{

    int i,j,k;

    ElemType e;

    LinkList p,p1;

    j=LocateVex(G,v);    //j是顶点v的序号

    if(j<0)        //v不是图G的顶点

        return ERROR;

    i=ListLength(G.vertices[j].firstarc);    //以v为出度的弧或者边数

    G.arcnum-=1;    //边或者弧数减1

    if(G.kind%2)    //网

        while(G.vertices[j].firstarc)    //以v为出度的弧或者边数

        {

            ListDelete(G.vertices[j].firstarc,1,e);        //删除链表的第一个结点,并且将值赋给e

            free(e,info);        //释放动态生成的权值空间

        }

    else  //图

        DestroyList(G.vertices[j].firstarc);    //销毁弧或者边链表

    G.vexnum--;        

    for(i=j;j<G.vexnum;i++)//顶点v后面的顶点前移

        G.vertices[i]=G.vertices[i+1];

    for(i=0;i<G.vexnum;i++)        //删除以v为入度的弧或边且必要时修改表结点的顶点位置值

    {

        e.adjvex=j;

        p=Point(G.vertices[i].firstarc,e,equalvex,p1);

        if(p)    //顶点i的邻接表上有v为入度的结点

        {

            if(p1)    //    p1指向p所指结点的前驱

                p1->next=p->next;    //从链表中删除p所指结点

            else    //    p指向首元结点

                G.vertices[i].firstarc=p->next;        //头结点指向下一结点

            if(G.kind<2)    //有向

            {

                G.arcnum--;        

                if(G.kind==1)

                    free(p->data.info);

            }

            free(p);    //释放v为入度的结点

        }

        for(k=j+1;k<=G.vexnum;k++)        //对于adjvex域>j的结点,其序号-1

            {

                e.adjvex=k;

                p=Point(G.vertices[i].firstarc,e,equalvex,p1);        //Point()

                if(p)

                    p->data.adjvex--;    //序号-1(因为前移)

            }

    }

    return OK;

}

//在G中增添弧<v,w>,若G是无向的,则还增添对称弧<w,v>

Status InsertArc(ALGraph &G,VertexType v,VertexType w)

{

    ELemType e;

    int i,j;

    i=LocateVex(G,v);//弧尾或边的序号

    j=LocateVex(G,w);    //弧头或者边的序号

    if(i<0||j<0)

        return ERROR;

    G.arcnum++;    //图G的弧或者边的数目加1

    e.adjvex=j;

    e.info=NULL;    //初值

    if(G.kind%2)    //网

    {

        e.info=(int *)malloc(sizeof(int));

        printf("请输入弧(边)%s->%s的权值:",v,w);

        scanf("%d",e.info);

    }

    ListInsert(G.vertices[i].firstarc,1,e);        //将e插在弧尾的表头

    if(G.kind>=2)

    {

        e.adjvex=i;

        ListInsert(G.vertices[j].firstarc,1,e);    

    }

    return OK;

}

//在G中删除弧<v,w>,若G是无向的,则还删除对称弧<w,v>

Status DeleteArc(ALGraph &G,VertexType v,VertexType w)

{

    int i,j;

    Status k;

    ELemType e;

    i=LocateVex(G,v)    //    i是顶点v(弧尾)的序号

    j=LocateVex(G,w);    //j是顶点w(弧头)的序号的序号

    if(i<0||j<0||i==j)

        return ERROR;

    e.adjvex=j;

    k=DeleteElem(G.vertices[i].firstarc,e,equalvex);    //    

    if(k)        //删除成功

    {

        G.arcnum--;        //弧或者边减1

        if(G.kind%2)    //网

            free(e.info);

        if(G.kind>=2)        //无向,删除对称弧《w,v》

        {

            e.adjvex=i;

            DeleteElem(G.vertices[i].firstarc,e,equalvex);

        }

        return Ok;

    }

    else    //没找到待删除的弧

        return ERROR;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息