圖的儲存形式——鄰接表

來源:互聯網
上載者:User

標籤:des   style   class   blog   code   http   

鄰接表:鄰接表是圖的一種鏈式儲存結構。在鄰接表中,對圖中每個頂點建立一個單鏈表,第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;}

測試:考慮以下有向圖:




聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.