1. 程式人生 > >圖的鄰接表儲存及基本操作

圖的鄰接表儲存及基本操作

圖的儲存方式有很多種,這裡事宜鄰接表儲存為例實現的。圖的基本操作包括初始化一個空圖、插入一節點、插入條邊、深度優先遍歷、廣度優先遍歷、銷燬圖等

#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR -1
#define MAX_VEX 10//最大頂點數
typedef int InfoType;
typedef char VexType;//頂點的型別
typedef int WeightType;//權值的型別

圖的種類(有向圖、無向圖、加權有向圖、加權無向圖),採用列舉法

typedef enum
{ DG = 1, AG, WDG, WAG//有向圖 無向圖 帶權有向圖 帶權無向圖 }GraphKind;

鄰接表的前半部分是順序表,所以定義一個順序表的結構體

typedef struct VexNode
{
    VexType data;//頂點的值
    int indegree;//頂點的度
    LinkNode *firstarc;//指向第一個表節點,有向圖是入度或出度或沒有
}VexNode;//頂點節點型別定義

鄰接表後半部分是連結串列,所以定一個連結串列的結構體

typedef struct LinkNode
{
    int adjvex;//鄰接點在頭結點陣列中的位置(下標)
InfoType info;//節點資訊 如權值 struct LinkNode *nextarc;//指向下一個表節點 }LinkNode;

接下來定義圖的結構體

typedef struct
{
    GraphKind kind;
    int vexnum;//頂點的個數
    VexNode AdjList[MAX_VEX];//頭結點的型別的陣列
}ALGraph;

在圖的一系列基本操作中需要佇列的幫助

//佇列的結構體
typedef struct SqQueue
{
    VexType array[MAX_VEX];
    int front;
    int
rear; }SqQueue; //初始化一個空佇列 SqQueue Creat_SqQueue() { SqQueue Q; Q.front = 0; Q.rear = 0; return Q; } //入佇列 若成功返回1 否則返回-1 int InsertQueue(SqQueue *Q, VexType e) { if ((Q->rear+1)%MAX_VEX == Q->front) { printf("The queue is full.\n"); return ERROR; } else { Q->array[Q->rear] = e; Q->rear = (Q->rear + 1) % MAX_VEX; //printf("Insert success!\n\n"); } return OK; } //出佇列 若成功返回彈出的元素 若不成功返回-1 VexType DeletaQueue(SqQueue *Q) { VexType e = 0; if (Q->front == Q->rear) { printf("This queue is empty!\n"); return ERROR; } else { e = Q->array[Q->front]; Q->front = (Q->front + 1) % MAX_VEX; //printf("Delete success!\n"); } return e; }

建立一個空圖

ALGraph CreatGraph() {
    ALGraph G;
    int i;//迴圈變數
    int a = 0;
    printf("1.DG\n2.AG\n3.WDG\n4.WAG\n");
    printf("please enter the type of graph(according to the code):\n");
    scanf("%d", &a);//確定圖的型別
    switch (a)
    {
    case 1:
        G.kind = DG;
        break;
    case 2:
        G.kind = AG;
        break;
    case 3:
        G.kind = WDG;
        break;
    case 4:
        G.kind = WAG;
        break;
    default:
        printf("The type of the graph is error\n");
        break;
    }
    G.vexnum = 0;//結點個數置為0
    for (i = 0; i < MAX_VEX; i++)//把所有節點的度置為0
    {
        G.AdjList[i].indegree = 0;
        G.AdjList[i].firstarc = NULL;
    }
    return G;
}

插入節點時需要判斷節點是否在,若不存在插入,如存在插入失敗

//定位節點  若存在返回1  若不存在返回-1
int LocateVex(ALGraph *G, VexType v) {
    int i = 0;
    int a = 0;
    printf("v = %c\n", v);
    for (i = 0; i < G->vexnum; i++)
    {
        if (G->AdjList[i].data == v)
        {
            a++;
            break;
        }
    }
    if (a == 0)
    {
        return ERROR;
    }
    return OK;
}

在圖中插入一個節點

void InsertVex(ALGraph *G){
    int res = 0;
    if (G->vexnum + 1 == MAX_VEX)
    {
        printf("The graph is overflow!\n");
    }
    else
    {
        VexType u = '\0';
        printf("please enter data:\n");
        getchar();
        scanf("%c", &u);
        res = LocateVex(G, u);
        if (res == -1)//沒有節點   新增
        {
            G->AdjList[G->vexnum].data = u;
            G->AdjList[G->vexnum].firstarc = NULL;
            G->vexnum++;
            //printf("insert vertex success\n");
        }
        else
        {
            printf("insert vertex fail\n");
        }
    }
}

在圖中插入一條邊時,要判斷圖的型別,不同的型別,插入操作是不一樣的

void InsertArc(ALGraph *G) {
    if (G->kind == DG)//有向圖
    {
        LinkNode *p;
        LinkNode *r;
        int tail = 0;//弧尾(起點)
        int head = 0;//弧頭(終點)
        p = (LinkNode *)malloc(sizeof(LinkNode));
        printf("please enter the tail:");
        scanf("%d", &tail);
        printf("please enter the head:");
        scanf("%d", &head);
        if (tail < G->vexnum && head < G->vexnum)
        {
            p->adjvex = head;
            p->nextarc = NULL;
            p->info = 0;
            r = G->AdjList[tail].firstarc;
            p->nextarc = r;
            G->AdjList[tail].firstarc = p;
            G->AdjList[tail].indegree++;
            printf("insert arc success\n");
        }
        else
        {
            printf("vertex is not exit.");
        }
    }
    else if(G->kind == AG)//無向圖
    {
        LinkNode *p;
        LinkNode *q;
        LinkNode *r;
        LinkNode *s;
        int tail = 0;
        int head = 0;
        p = (LinkNode *)malloc(sizeof(LinkNode));
        q = (LinkNode *)malloc(sizeof(LinkNode));
        s = (LinkNode *)malloc(sizeof(LinkNode));
        printf("please enter the tail:");
        scanf("%d", &tail);
        printf("please enter the head:");
        scanf("%d", &head);
        if (tail < G->vexnum && head < G->vexnum)
        {
            p->adjvex = head;
            p->info = 0;
            p->nextarc = NULL;
            r = G->AdjList[tail].firstarc;
            p->nextarc = r;
            G->AdjList[tail].firstarc = p;

            s->adjvex = tail;
            s->info = 0;
            q = G->AdjList[head].firstarc;
            s->nextarc = q;
            G->AdjList[head].firstarc = s;

            G->AdjList[tail].indegree++;
            G->AdjList[head].indegree++;
            printf("insert arc success\n");
        }
        else
        {
            printf("vertex is not exit.\n");
        }

    }
    else if (G->kind == WDG)//加權有向圖
    {
        LinkNode *p;
        LinkNode *r;
        int info = 0;
        int tail = 0;//弧尾(起點)
        int head = 0;//弧頭(終點)
        p = (LinkNode *)malloc(sizeof(LinkNode));
        printf("please enter the tail:");
        scanf("%d", &tail);
        printf("please enter the head:");
        scanf("%d", &head);
        printf("please enter the information:");
        scanf("%d", &info);
        if (tail < G->vexnum && head < G->vexnum)
        {
            p->adjvex = head;
            p->nextarc = NULL;
            p->info = info;
            r = G->AdjList[tail].firstarc;
            p->nextarc = r;
            G->AdjList[tail].firstarc = p;
            G->AdjList[tail].indegree++;
            printf("insert arc success\n");
        }
        else
        {
            printf("vertex is not exit.\n");
        }

    }
    else if(G->kind == WAG)//加權無向圖
    {
        LinkNode *p;
        LinkNode *q;
        LinkNode *r;
        LinkNode *s;
        int info = 0;
        int tail = 0;
        int head = 0;
        p = (LinkNode *)malloc(sizeof(LinkNode));
        q = (LinkNode *)malloc(sizeof(LinkNode));
        s = (LinkNode *)malloc(sizeof(LinkNode));
        printf("please enter the tail:");
        scanf("%d", &tail);
        printf("please enter the head:");
        scanf("%d", &head);
        printf("please enter the information:");
        scanf("%d", &info);
        if (tail < G->vexnum && head < G->vexnum)
        {
            p->adjvex = head;
            p->nextarc = NULL;
            p->info = info;
            r = G->AdjList[tail].firstarc;
            p->nextarc = r;
            G->AdjList[tail].firstarc = p;

            s->adjvex = tail;
            s->info = info;
            q = G->AdjList[head].firstarc;
            s->nextarc = q;
            G->AdjList[head].firstarc = s;

            G->AdjList[tail].indegree++;
            G->AdjList[head].indegree++;
            printf("insert arc success\n");
        }
        else
        {
            printf("vertex is not exit.\n");
        }
    }
    else
    {
        printf("The type of the graph is error\n");
    }
}

圖的深度優先遍歷

void DFSTraverse(ALGraph *G, int v, int visit[]) {
    LinkNode *p;

    if (visit[v] == 0)
    {
        printf("%c\n", G->AdjList[v].data);
        visit[v] = 1;
        p = G->AdjList[v].firstarc;

        while (p != NULL)
        {
            if (visit[p->adjvex] == 0)
            {
                DFSTraverse(G, p->adjvex, visit);
            }
            p = p->nextarc;
        }
    }
}

圖的廣度優先遍歷

void BFSTraverse(ALGraph *G){
    int i = 0;//迴圈變數
    int k = 0;//迴圈變數
    SqQueue Q = Creat_SqQueue();
    //visited為訪問標誌陣列,為0則該節點沒被訪問過,為1則被訪問過
    int visited[MAX_VEX];
    LinkNode *p;
    for (i = 0; i < MAX_VEX; i++)//訪問標誌初始化
    {
        visited[i] = 0;
    }
    //廣度優先遍歷圖
    for (k = 0; k < G->vexnum; k++)
    {
        if (visited[k] == 0)//若該節點沒有被訪問過
        {
            InsertQueue(&Q, k);
            visited[k] = 1;
            if (G->AdjList[k].firstarc != NULL)
            {
                p = G->AdjList[k].firstarc;
                while (p != NULL)
                {
                    if(visited[p->adjvex] == 0)
                    {
                        InsertQueue(&Q, p->adjvex);
                        visited[p->adjvex] = 1;
                    }
                    p = p->nextarc;
                }
            }
        }
        else//若該節點被訪問過
        {
            if (G->AdjList[k].firstarc != NULL)
            {
                p = G->AdjList[k].firstarc;
                while (p != NULL)
                {
                    if(visited[p->adjvex] == 0)
                    {
                        InsertQueue(&Q, p->adjvex);
                        visited[p->adjvex] = 1;
                    }
                    p = p->nextarc;
                }
            }
        }
    }
    while (Q.front != Q.rear)//迴圈彈出佇列中的元素
    {
        printf("%c\n", G->AdjList[DeletaQueue(&Q)].data);
    }
}

銷燬一個圖

int DestroyGeaph(ALGraph *G) {
    int i = 0;//迴圈變數
    for (i = 0; i < G->vexnum; i++)
    {
        G->AdjList[i].data = 0;
        G->AdjList[i].indegree = 0;
        G->AdjList[i].firstarc = NULL;
    }
    G->vexnum = 0;
    return OK;
}

以鄰接表的形式輸出圖

void OutPutGraph(ALGraph G)
{
    int i = 0;//迴圈變數
    printf("value\tindegree\tfirstarc\n");
    for (i = 0; i < G.vexnum; i++)
    {
        printf("%c\t", G.AdjList[i].data);
        printf("%d\t\t", G.AdjList[i].indegree);
        LinkNode *p;
        p = G.AdjList[i].firstarc;
        while (p != NULL)
        {
            printf("->");
            printf("%c \t", G.AdjList[p->adjvex].data);
            p = p->nextarc;
        }
        printf("\n");
        printf("----------------------\n");
    }
}

示例:
這裡寫圖片描述
執行結果:
這裡寫圖片描述
以上就是圖的基本操作了,主方法就不寫了,大家根據可以自己的需要寫,希望大家看了以後能幫得上忙。