图的存储形式——邻接表

来源:互联网 发布:监控网络矩阵 编辑:程序博客网 时间:2024/06/18 07:28

邻接表:邻接表是图的一种链式存储结构。在邻接表中,对图中每个顶点建立一个单链表,第i个单链表中的节点表示依附于顶点vi的边(对有向图是以顶点vi为尾的弧)。每个结点有三个域组成,其中邻接点域指示与顶点vi邻接的点在途中的位置,链域指示下一条边或者弧的结点;数据域存储和边或者弧相关的信息,如权值等。每个链表上附设一个表头结点。在表头结点中,除了设置链域指向链表第一个结点之外,还设置有存储顶点vi的名。如下所示:


实现:

/**************************************图的存储之邻接表by Rowandjj2014/6/23**************************************/#include<iostream>using namespace std;#define MAX_VERTEX_NUM 20//最大顶点数typedef enum{DG,DN,AG,AN}GraphKind;//有向图、有向网、无向图、无向网typedef struct _ARCNODE_//表节点(弧){    int adjvex;//邻接点序号    struct _ARCNODE_ *nextarc;//指向下一条弧    int info;//信息(权值)  }ArcNode;typedef struct _VNODE_//头结点{    char data;//顶点名    ArcNode *firstarc;//指向第一条弧}VNode,AdjList[MAX_VERTEX_NUM];typedef struct _ALGRAPH_//邻接表{    AdjList vertices;//邻接表    int vexnum;//顶点数    int arcnum;//弧数    GraphKind kind;//图的种类}ALGraph;void (*VisitFunc)(char);  //全局函数指针 bool visited[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */void Visit(char p){    cout<<p<<" ";}//-----------------操作-------------------------------------int LocateVex(ALGraph G,char u);//若G中存在顶点u,则返回该顶点在图中位置;否则返回-1bool CreateGraph(ALGraph* G);//采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图)void DestroyGraph(ALGraph* G);//销毁图Gchar GetVex(ALGraph G,int v);//通过序号v得到顶点名bool PutVex(ALGraph* G,char v,char value);//对v赋新值valueint FirstAdjVex(ALGraph G,char v);//返回顶点v的第一个邻接顶点的序号int NextAdjVex(ALGraph G,char v,char w);//返回v的(相对于w的)下一个邻接顶点的序号,若w是v的最后一个邻接点,则返回-1void InsertVex(ALGraph* G,char v);//在图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做)             bool DeleteVex(ALGraph* G,char v);//删除G中顶点v及其相关的弧bool InsertArc(ALGraph* G,char v,char w);//在G中增添弧<v,w>,若G是无向的,则还增添对称弧<w,v>bool DeleteArc(ALGraph* G,char v,char w);//在G中删除弧<v,w>,若G是无向的,则还删除对称弧<w,v>void DFSTravel(ALGraph* G,void (*Visit)(char));//深度优先void DFS(ALGraph G,int v);void BFSTravel(ALGraph G,void (*Visit)(char));//广度优先void Display(ALGraph G);//打印图//----------------辅助队列------------------------------------------#define MAX_QUEUE_SIZE 20typedef struct _QUEUENODE_{    int data;    struct _QUEUENODE_ *next;}QueueNode;typedef struct _QUEUE_{    QueueNode *pHead;    QueueNode *pTail;    int size;}Queue;bool InitQueue(Queue *Q);bool DestroyQueue(Queue *Q);bool DeQueue(Queue *Q,int* e);bool EnQueue(Queue *Q, int e);bool QueueEmpty(Queue Q);//------------------------------------------------------------------bool InitQueue(Queue *Q){    Q->pHead = Q->pTail = (QueueNode *)malloc(sizeof(QueueNode));    if(!Q->pHead)    {        return false;    }    Q->pHead->next = NULL;    Q->size = 0;    return true;}bool EnQueue(Queue *Q, int e){    QueueNode *node = (QueueNode*)malloc(sizeof(QueueNode));    node->data = e;    node->next = NULL;    Q->pTail->next = node;    Q->pTail = node;    Q->size++;    return true;}bool DeQueue(Queue *Q,int* e){    QueueNode *node = Q->pHead->next;    if(node)    {        *e = node->data;        Q->pHead->next = node->next;        if(Q->pTail == node)        {            Q->pTail = Q->pHead;        }        free(node);        Q->size--;    }    return true;}bool QueueEmpty(Queue Q){    return Q.size == 0;}bool DestroyQueue(Queue *Q){    QueueNode *pTemp = Q->pHead->next;    while(pTemp != NULL)    {        Q->pHead->next = pTemp->next;        free(pTemp);        pTemp = Q->pHead->next;    }    free(Q->pHead);    Q->size = 0;    return true;}//------------------------------------------------------------------int LocateVex(ALGraph G,char u){    int i;    for(i = 0; i < G.vexnum; i++)    {        if(u == G.vertices[i].data)        {            return i;        }    }    return -1;}bool CreateGraph(ALGraph* G){    int i,j,k;    int w;//权值    char va,vb;//弧尾、弧头    ArcNode *p;//弧    cout<<"请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ";    scanf("%d",&(*G).kind);    cout<<"请输入图的顶点数,边数: ";    cin>>G->vexnum;    cin>>G->arcnum;    cout<<"请输入顶点值:"<<endl;    //构造顶点    for(i = 0; i < G->vexnum; i++)    {        cin>>G->vertices[i].data;        G->vertices[i].firstarc = NULL;    }    if(G->kind == 1 || G->kind == 3)//网    {        cout<<"请顺序输入每条弧(边)的权值、弧尾和弧头:\n";    }else//图    {        cout<<"请顺序输入每条弧(边)的弧尾和弧头\n";    }    //构造表节点链表    for(k = 0; k < G->arcnum; k++)    {        if(G->kind == 1 || G->kind == 3)//网        {                cin>>w;            cin>>va;            cin>>vb;        }else//图        {            cin>>va;            cin>>vb;        }        //定位弧尾弧头的位置        i = LocateVex(*G,va);        j = LocateVex(*G,vb);            p = (ArcNode *)malloc(sizeof(ArcNode));        p->adjvex = j;                if(G->kind == 1 || G->kind == 3)//网        {            p->info = w;//权值        }else        {            p->info = NULL;        }        //插入表        p->nextarc = G->vertices[i].firstarc;//插在表头        G->vertices[i].firstarc = p;        //如果是无向图或者无向网,还需要增加对称结点        if(G->kind == 2 || G->kind == 3)        {            p = (ArcNode *)malloc(sizeof(ArcNode));            p->adjvex = i;                        if(G->kind == 3)//若是无向网,还需要权值            {                p->info = w;            }else            {                p->info = NULL;            }                        //插入表            p->nextarc = G->vertices[j].firstarc;            G->vertices[j].firstarc = p;        }    }    return true;}void Display(ALGraph G){    ArcNode *p;    int i;    switch(G.kind)    {    case DG:        cout<<"有向图";        break;    case AG:        cout<<"无向图";        break;    case DN:        cout<<"有向网";        break;    case AN:        cout<<"无向网";        break;    default:        break;    }    cout<<endl;    cout<<"顶点:"<<endl;    for(i = 0; i < G.vexnum; i++)    {        cout<<G.vertices[i].data<<" ";    }    cout<<endl;    //边    cout<<"边:"<<endl;    for(i = 0; i < G.vexnum; i++)    {        p = G.vertices[i].firstarc;        while(p)        {            if(G.kind == 0 || G.kind == 1)//有向            {                cout<<G.vertices[i].data<<" "<<G.vertices[p->adjvex].data;                if(G.kind == 1)//有向网                {                    cout<<" "<<p->info;                }            }else//无向            {                if(i < p->adjvex)//不重复打印                {                    cout<<G.vertices[i].data<<" "<<G.vertices[p->adjvex].data;                    if(G.kind == 3)//无向网                    {                        cout<<" "<<p->info;                    }                    }            }            cout<<endl;            p = p->nextarc;        }    }}void DestroyGraph(ALGraph* G){    ArcNode *p,*q;    int i;        for(i = 0; i < G->vexnum; i++)    {        p = G->vertices[i].firstarc;        while(p)        {            q = p->nextarc;            free(p);            p = q;        }    }    G->arcnum = 0;    G->vexnum = 0;}char GetVex(ALGraph G,int v){    if(v>=G.vexnum || v<0)    {        exit(0);    }    return G.vertices[v].data;}bool PutVex(ALGraph* G,char v,char value){    int i = LocateVex(*G,v);    if(i == -1)    {        return false;    }    G->vertices[i].data = value;    return true;}int FirstAdjVex(ALGraph G,char v){    int i = LocateVex(G,v);    if(i < 0)    {        return -1;    }    ArcNode *arcNode = G.vertices[i].firstarc;    if(arcNode == NULL)    {        return -1;    }    return arcNode->adjvex;}int NextAdjVex(ALGraph G,char v,char w){    int i,j;    i = LocateVex(G,v);    j = LocateVex(G,w);    ArcNode *p = G.vertices[i].firstarc;    while(p && p->adjvex != j)    {        p = p->nextarc;    }    if(!p || !p->nextarc)//没找到w或w是最后一个邻接点    {        return -1;    }    else    {        return p->nextarc->adjvex;    }}void InsertVex(ALGraph* G,char v){    G->vertices[G->vexnum].data = v;    G->vertices[G->vexnum].firstarc = NULL;    G->vexnum++;}bool DeleteVex(ALGraph* G,char v){    int i,j;    ArcNode *p,*q;    //1.删除邻接表中顶点为v的那一行所有数据,更改弧总数,顶点总数    i = LocateVex(*G,v);    if(i < 0 || i >= G->vexnum)//不合法的位置    {        return false;    }    p = G->vertices[i].firstarc;    while(p)//依次删除弧    {        q = p->nextarc;        free(p);        p = q;        G->arcnum--;    }    G->vexnum--;    //2.更改顶点v之后的顶点在数组中的位置(前移一位)    for(j = i; j < G->vexnum; j++)    {        G->vertices[j] = G->vertices[j+1];    }    //3.遍历剩下的邻接表,找到包含顶点v的弧或者边,删除之。另外需要注意,对遍历的每个弧/边,视情况更新序号    for(j = 0; j < G->vexnum; j++)    {        p = G->vertices[j].firstarc;//p指向遍历的顶点的第一条弧或者边        while(p)        {            if(p->adjvex == i)//如果找到指向已删除顶点的弧或者边            {                if(p == G->vertices[j].firstarc)//如果待删除的结点是第一个结点                {                    G->vertices[j].firstarc = p->nextarc;                    free(p);                    p = G->vertices[j].firstarc;                    if(G->kind <= 1)//如果是有向的,则还需更改弧数                    {                        G->arcnum--;                    }                }else//不是第一个结点                {                    q->nextarc = p->nextarc;                    free(p);                    p = q->nextarc;                    if(G->kind <= 1)//如果是有向的,则还需更改弧数                    {                        G->arcnum--;                    }                }            }else//如果当前弧并不是要找的弧,那么继续向后遍历            {                if(p->adjvex > i)//(很关键)更新序号                {                    p->adjvex--;                }                q = p;                p = p->nextarc;//指向下一条弧            }        }    }    return true;}bool InsertArc(ALGraph* G,char v,char w){    int i,j,weight;    ArcNode *arcNode;    //1.得到v、w的在邻接表中的序号    i = LocateVex(*G,v);    j = LocateVex(*G,w);    if(i<0 || j<0)    {        return false;    }    G->arcnum++;    if(G->kind == 1 || G->kind == 3)    {        cout<<"输入权值:";        cin>>weight;//输入权值    }    //2.生成一个弧结点,插入到顶点v的第一个邻接点的位置(如果是网的话,需要用户输入权值)    arcNode = (ArcNode*)malloc(sizeof(ArcNode));    arcNode->adjvex = j;    if(G->kind == 1 || G->kind == 3)    {        arcNode->info = weight;    }    else    {        arcNode->info = NULL;    }        arcNode->nextarc = G->vertices[i].firstarc;    G->vertices[i].firstarc = arcNode;    //3.如果是无向的,那么还需生成对称节点,并插到合适位置    if(G->kind >= 2)    {        arcNode = (ArcNode *)malloc(sizeof(ArcNode));        arcNode->adjvex = i;        if(G->kind == 3)//无向网        {            arcNode->info = weight;        }        else        {            arcNode->info = NULL;        }        arcNode->nextarc = G->vertices[j].firstarc;        G->vertices[j].firstarc = arcNode;    }        return true;}bool DeleteArc(ALGraph* G,char v,char w){    int i,j;    ArcNode *p,*q;    //1.得到v、w的在邻接表中的序号    i = LocateVex(*G,v);    j = LocateVex(*G,w);    if(i < 0 || j < 0)    {        return false;    }    //2.删除v-w    p = G->vertices[i].firstarc;    while(p && p->adjvex!=j)    {        q = p;        p = p->nextarc;    }    if(p && p->adjvex==j)//找到弧<v-w>    {        if(p == G->vertices[i].firstarc)//p指的是第一条弧        {            G->vertices[i].firstarc = p->nextarc;        }        else        {            q->nextarc = p->nextarc;        }        free(p);        G->arcnum--;    }    //3.若是无向,则还删除w-v    if(G->kind >= 2)    {        p = G->vertices[j].firstarc;        while(p && p->adjvex!=i)        {            q = p;            p = p->nextarc;        }        if(p && p->adjvex==i)//找到弧<w-v>        {            if(p == G->vertices[j].firstarc)//p指的是第一条弧            {                G->vertices[j].firstarc = p->nextarc;            }            else            {                q->nextarc = p->nextarc;            }            free(p);        }    }    return true;}void DFSTravel(ALGraph* G,void (*Visit)(char)){    int i;    VisitFunc = Visit;    for(i = 0; i < G->vexnum; i++)    {        visited[i] = false;    }    for(i = 0; i < G->vexnum; i++)    {        if(!visited[i])        {            DFS(*G,i);        }    }    cout<<endl;}void DFS(ALGraph G,int v){    int i;    char v1,w1;    v1 = GetVex(G,v);    visited[v] = true;    VisitFunc(G.vertices[v].data);    for(i = FirstAdjVex(G,v1);i>=0; i = NextAdjVex(G,v1,w1 = GetVex(G,i)))    {        if(!visited[i])        {            DFS(G,i);        }    }}void BFSTravel(ALGraph G,void (*Visit)(char)){    Queue q;    InitQueue(&q);    char w1,u1;    int i,u,w;    for(i = 0; i < G.vexnum; i++)    {        visited[i] = false;    }        for(i = 0; i < G.vexnum; i++)    {        if(!visited[i])        {            visited[i] = true;            Visit(G.vertices[i].data);            EnQueue(&q,i);                        while(!QueueEmpty(q))            {                DeQueue(&q,&u);                u1 = GetVex(G,u);                for(w = FirstAdjVex(G,u1);w>=0;w = NextAdjVex(G,u1,w1=GetVex(G,w)))                {                    if(!visited[w])                    {                        visited[w] = true;                        Visit(G.vertices[w].data);                        EnQueue(&q,w);                    }                                    }            }        }    }    DestroyQueue(&q);    cout<<endl;}int main(){        ALGraph graph;    CreateGraph(&graph);    Display(graph);        cout<<"深度优先:"<<endl;    DFSTravel(&graph,Visit);    cout<<"广度优先:"<<endl;    BFSTravel(graph,Visit);    DestroyGraph(&graph);        return 0;}

测试:
考虑以下有向图:





2 0
原创粉丝点击