数据--第41棵 - 图的存储结构

第41棵 - 图的存储结构

1. 邻接矩阵法

用一维数组存储顶点--描述顶点相关的数据。

用二维数组存储边--描述顶点的边。

设图A = (V,E)是一个有n个顶点的图,图的邻接矩阵为Edge[n][n],则:Edge[i][j] = W,W>0,i和j连接;Edge[i][j] = 0,i == j 或者i和j不链接。

注:W为权值,当需要权值时,取W为1表示结点间连接。

无向图的邻接矩阵是对称的。

有向图的邻接矩阵可能是不对称的。

2. 邻接矩阵法的头结点

记录定点的个数。

记录与顶点相关的数据描述。

记录描述边集的二维数组。

typedef struct _tag_MGraph

{

int count;

MVertex** v;

int** matrix;

}TMGraph;

问题:如何根据顶点数目,动态创建二维数组?

3. 动态申请二维数组的原理

通过二级指针动态申请一位数组。

通过一级指针申请数据空间。

将一维指针数组中的指针连接到数据空间。

int** malloc2d(int row, int col)

{

         int** ret = (int**)malloc(sizeof(int*) * row);

         int* p = (int*)malloc(sizeof(int) * row *col);

         int i = 0;

         if(p && ret)

         {

                  for(i=0;i<row;i++)

                  {

                           ret[i] = p + i * col;    

                  }       

         }       

         else

         {

                  free(ret);

                  fre(p);

                  ret = NULL;      

         }

         return ret;

}

4. 程序——邻接矩阵法实现图结构

main.c

#include <stdio.h>

#include <stdlib.h>

#include "LGraph.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

void print_data(LVertex* v)

{

    printf("%s", (char*)v);

}

int main(int argc, char *argv[])

{

    LVertex* v[] = {"A", "B", "C", "D", "E", "F"};

    LGraph* graph = LGraph_Create(v, 6);

   

    LGraph_AddEdge(graph, 0, 1, 1);

    LGraph_AddEdge(graph, 0, 2, 1);

    LGraph_AddEdge(graph, 0, 3, 1);

    LGraph_AddEdge(graph, 1, 5, 1);

    LGraph_AddEdge(graph, 1, 4, 1);

    LGraph_AddEdge(graph, 2, 1, 1);

    LGraph_AddEdge(graph, 3, 4, 1);

    LGraph_AddEdge(graph, 4, 2, 1);

   

    LGraph_Display(graph, print_data);

   

    LGraph_DFS(graph, 0, print_data);

    LGraph_BFS(graph, 0, print_data);

   

    LGraph_Destroy(graph);

   

         return 0;

}

LGraph.h

#ifndef _LGRAPH_H_

#define _LGRAPH_H_

typedef void LGraph;

typedef void LVertex;

typedef void (LGraph_Printf)(LVertex*);

LGraph* LGraph_Create(LVertex** v, int n);

void LGraph_Destroy(LGraph* graph);

void LGraph_Clear(LGraph* graph);

int LGraph_AddEdge(LGraph* graph, int v1, int v2, int w);

int LGraph_RemoveEdge(LGraph* graph, int v1, int v2);

int LGraph_GetEdge(LGraph* graph, int v1, int v2);

int LGraph_TD(LGraph* graph, int v);

int LGraph_VertexCount(LGraph* graph);

int LGraph_EdgeCount(LGraph* graph);

void LGraph_DFS(LGraph* graph, int v, LGraph_Printf* pFunc);

void LGraph_BFS(LGraph* graph, int v, LGraph_Printf* pFunc);

void LGraph_Display(LGraph* graph, LGraph_Printf* pFunc);

#endif

LGraph.c

#include <malloc.h>

#include <stdio.h>

#include "LGraph.h"

#include "LinkList.h"

#include "LinkQueue.h"

typedef struct _tag_LGraph

{

    int count;

    LVertex** v;

    LinkList** la;

} TLGraph;

typedef struct _tag_ListNode

{

    LinkListNode header;

    int v;

    int w;

} TListNode;

static void recursive_dfs(TLGraph* graph, int v, int visited[], LGraph_Printf* pFunc)

{

    int i = 0;

   

    pFunc(graph->v[v]);

   

    visited[v] = 1;

   

    printf(", ");

   

    for(i=0; i<LinkList_Length(graph->la[v]); i++)

    {

        TListNode* node = (TListNode*)LinkList_Get(graph->la[v], i);

       

        if( !visited[node->v] )

        {

            recursive_dfs(graph, node->v, visited, pFunc);

        }

    }

}

static void bfs(TLGraph* graph, int v, int visited[], LGraph_Printf* pFunc)

{

    LinkQueue* queue = LinkQueue_Create();

   

    if( queue != NULL )

    {

        LinkQueue_Append(queue, graph->v + v);

       

        visited[v] = 1;

       

        while( LinkQueue_Length(queue) > 0 )

        {

            int i = 0;

           

            v = (LVertex**)LinkQueue_Retrieve(queue) - graph->v;

           

            pFunc(graph->v[v]);

           

            printf(", ");

           

            for(i=0; i<LinkList_Length(graph->la[v]); i++)

            {

                TListNode* node = (TListNode*)LinkList_Get(graph->la[v], i);

               

                if( !visited[node->v] )

                {

                    LinkQueue_Append(queue, graph->v + node->v);

                   

                    visited[node->v] = 1;

                }

            }

        }

    }

   

    LinkQueue_Destroy(queue);

}

LGraph* LGraph_Create(LVertex** v, int n)  // O(n)

{

    TLGraph* ret = NULL;

    int ok = 1;

   

    if( (v != NULL ) && (n > 0) )

    {

        ret = (TLGraph*)malloc(sizeof(TLGraph));

       

        if( ret != NULL )

        {

            ret->count = n;

           

            ret->v = (LVertex**)calloc(n, sizeof(LVertex*));

           

            ret->la = (LinkList**)calloc(n, sizeof(LinkList*));

           

            ok = (ret->v != NULL) && (ret->la != NULL);

           

            if( ok )

            {

                int i = 0;

               

                for(i=0; i<n; i++)

                {

                    ret->v[i] = v[i];

                }

               

                for(i=0; (i<n) && ok; i++)

                {

                    ok = ok && ((ret->la[i] = LinkList_Create()) != NULL);

                }

            }

           

            if( !ok )

            {

                if( ret->la != NULL )

                {

                    int i = 0;

                   

                    for(i=0; i<n; i++)

                    {

                        LinkList_Destroy(ret->la[i]);

                    }

                }

               

                free(ret->la);

                free(ret->v);

                free(ret);

               

                ret = NULL;

            }

        }

    }

   

    return ret;

}

void LGraph_Destroy(LGraph* graph) // O(n*n)

{

    TLGraph* tGraph = (TLGraph*)graph;

   

    LGraph_Clear(tGraph);

   

    if( tGraph != NULL )

    {

        int i = 0;

       

        for(i=0; i<tGraph->count; i++)

        {

            LinkList_Destroy(tGraph->la[i]);

        }

       

        free(tGraph->la);

        free(tGraph->v);

        free(tGraph);

    }

}

void LGraph_Clear(LGraph* graph) // O(n*n)

{

    TLGraph* tGraph = (TLGraph*)graph;

   

    if( tGraph != NULL )

    {

        int i = 0;

       

        for(i=0; i<tGraph->count; i++)

        {

            while( LinkList_Length(tGraph->la[i]) > 0 )

            {

                free(LinkList_Delete(tGraph->la[i], 0));

            }

        }

    }

}

int LGraph_AddEdge(LGraph* graph, int v1, int v2, int w) // O(1)

{

    TLGraph* tGraph = (TLGraph*)graph;

    TListNode* node = NULL;

    int ret = (tGraph != NULL);

   

    ret = ret && (0 <= v1) && (v1 < tGraph->count);

    ret = ret && (0 <= v2) && (v2 < tGraph->count);

    ret = ret && (0 < w) && ((node = (TListNode*)malloc(sizeof(TListNode))) != NULL);

   

    if( ret )

    {

       node->v = v2;

       node->w = w;

      

       LinkList_Insert(tGraph->la[v1], (LinkListNode*)node, 0);

    }

   

    return ret;

}

int LGraph_RemoveEdge(LGraph* graph, int v1, int v2) // O(n*n)

{

    TLGraph* tGraph = (TLGraph*)graph;

    int condition = (tGraph != NULL);

    int ret = 0;

   

    condition = condition && (0 <= v1) && (v1 < tGraph->count);

    condition = condition && (0 <= v2) && (v2 < tGraph->count);

   

    if( condition )

    {

        TListNode* node = NULL;

        int i = 0;

       

        for(i=0; i<LinkList_Length(tGraph->la[v1]); i++)

        {

            node = (TListNode*)LinkList_Get(tGraph->la[v1], i);

           

            if( node->v == v2)

            {

                ret = node->w;

               

                LinkList_Delete(tGraph->la[v1], i);

               

                free(node);

               

                break;

            }

        }

    }

   

    return ret;

}

int LGraph_GetEdge(LGraph* graph, int v1, int v2) // O(n*n)

{

    TLGraph* tGraph = (TLGraph*)graph;

    int condition = (tGraph != NULL);

    int ret = 0;

   

    condition = condition && (0 <= v1) && (v1 < tGraph->count);

    condition = condition && (0 <= v2) && (v2 < tGraph->count);

   

    if( condition )

    {

        TListNode* node = NULL;

        int i = 0;

       

        for(i=0; i<LinkList_Length(tGraph->la[v1]); i++)

        {

            node = (TListNode*)LinkList_Get(tGraph->la[v1], i);

           

            if( node->v == v2)

            {

                ret = node->w;

               

                break;

            }

        }

    }

   

    return ret;

}

int LGraph_TD(LGraph* graph, int v) // O(n*n*n)

{

    TLGraph* tGraph = (TLGraph*)graph;

    int condition = (tGraph != NULL);

    int ret = 0;

   

    condition = condition && (0 <= v) && (v < tGraph->count);

   

    if( condition )

    {

        int i = 0;

        int j = 0;

       

        for(i=0; i<tGraph->count; i++)

        {

            for(j=0; j<LinkList_Length(tGraph->la[i]); j++)

            {

                TListNode* node = (TListNode*)LinkList_Get(tGraph->la[i], j);

               

                if( node->v == v )

                {

                    ret++;

                }

            }

        }

       

        ret += LinkList_Length(tGraph->la[v]);

    }

   

    return ret;

}

int LGraph_VertexCount(LGraph* graph) // O(1)

{

    TLGraph* tGraph = (TLGraph*)graph;

    int ret = 0;

   

    if( tGraph != NULL )

    {

        ret = tGraph->count;

    }

   

    return ret;

}

int LGraph_EdgeCount(LGraph* graph) // O(n)

{

    TLGraph* tGraph = (TLGraph*)graph;

    int ret = 0;

   

    if( tGraph != NULL )

    {

        int i = 0;

       

        for(i=0; i<tGraph->count; i++)

        {

            ret += LinkList_Length(tGraph->la[i]);

        }

    }

   

    return ret;

}

void LGraph_DFS(LGraph* graph, int v, LGraph_Printf* pFunc)

{

    TLGraph* tGraph = (TLGraph*)graph;

    int* visited = NULL;

    int condition = (tGraph != NULL);

   

    condition = condition && (0 <= v) && (v < tGraph->count);

    condition = condition && (pFunc != NULL);

    condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL);

   

    if( condition )

    {

        int i = 0;

       

        recursive_dfs(tGraph, v, visited, pFunc);

       

        for(i=0; i<tGraph->count; i++)

        {

            if( !visited[i] )

            {

                recursive_dfs(tGraph, i, visited, pFunc);

            }

        }

       

        printf("\n");

    }

   

    free(visited);

}

void LGraph_BFS(LGraph* graph, int v, LGraph_Printf* pFunc)

{

    TLGraph* tGraph = (TLGraph*)graph;

    int* visited = NULL;

    int condition = (tGraph != NULL);

   

    condition = condition && (0 <= v) && (v < tGraph->count);

    condition = condition && (pFunc != NULL);

    condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL);

   

    if( condition )

    {

        int i = 0;

       

        bfs(tGraph, v, visited, pFunc);

       

        for(i=0; i<tGraph->count; i++)

        {

            if( !visited[i] )

            {

                bfs(tGraph, i, visited, pFunc);

            }

        }

       

        printf("\n");

    }

   

    free(visited);

}

void LGraph_Display(LGraph* graph, LGraph_Printf* pFunc) // O(n*n*n)

{

    TLGraph* tGraph = (TLGraph*)graph;

   

    if( (tGraph != NULL) && (pFunc != NULL) )

    {

        int i = 0;

        int j = 0;

       

        for(i=0; i<tGraph->count; i++)

        {

            printf("%d:", i);

            pFunc(tGraph->v[i]);

            printf(" ");

        }

       

        printf("\n");

       

        for(i=0; i<tGraph->count; i++)

        {

            for(j=0; j<LinkList_Length(tGraph->la[i]); j++)

            {

                TListNode* node = (TListNode*)LinkList_Get(tGraph->la[i], j);

               

                printf("<");

                pFunc(tGraph->v[i]);

                printf(", ");

                pFunc(tGraph->v[node->v]);

                printf(", %d", node->w);

                printf(">");

                printf(" ");              

            }

        }

       

        printf("\n");

    }

}

LinkList.h

LinkList.c

LinkQueue.h

LinkQueue.c

5. 邻接表示法

从一个顶点出发的边连接在同一个链表中。

每一个链表结点代表一条边,结点中保存边的另一个顶点的下标和权值。

6. 邻接链表发的头结点

记录定点个数。

记录与顶点相关的数据描述。

记录描述边集的链表数组。

typedef struct _tag_LGraph

{

int count;

LVertex** v;

LinkList** la;

}TLGraph;

7. 程序——邻接链表发实现图结构

main.c

#include <stdio.h>

#include <stdlib.h>

#include "MGraph.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

void print_data(MVertex* v)

{

    printf("%s", (char*)v);

}

int main(int argc, char *argv[])

{

    MVertex* v[] = {"A", "B", "C", "D", "E", "F"};

    MGraph* graph = MGraph_Create(v, 6);

   

    MGraph_AddEdge(graph, 0, 1, 1);

    MGraph_AddEdge(graph, 0, 2, 1);

    MGraph_AddEdge(graph, 0, 3, 1);

    MGraph_AddEdge(graph, 1, 5, 1);

    MGraph_AddEdge(graph, 1, 4, 1);

    MGraph_AddEdge(graph, 2, 1, 1);

    MGraph_AddEdge(graph, 3, 4, 1);

    MGraph_AddEdge(graph, 4, 2, 1);

   

    MGraph_Display(graph, print_data);

   

    MGraph_DFS(graph, 0, print_data);

    MGraph_BFS(graph, 0, print_data);

   

    MGraph_Destroy(graph);

   

         return 0;

}

MGraph.h

#ifndef _MGRAPH_H_

#define _MGRAPH_H_

typedef void MGraph;

typedef void MVertex;

typedef void (MGraph_Printf)(MVertex*);

MGraph* MGraph_Create(MVertex** v, int n);

void MGraph_Destroy(MGraph* graph);

void MGraph_Clear(MGraph* graph);

int MGraph_AddEdge(MGraph* graph, int v1, int v2, int w);

int MGraph_RemoveEdge(MGraph* graph, int v1, int v2);

int MGraph_GetEdge(MGraph* graph, int v1, int v2);

int MGraph_TD(MGraph* graph, int v);

int MGraph_VertexCount(MGraph* graph);

int MGraph_EdgeCount(MGraph* graph);

void MGraph_DFS(MGraph* graph, int v, MGraph_Printf* pFunc);

void MGraph_BFS(MGraph* graph, int v, MGraph_Printf* pFunc);

void MGraph_Display(MGraph* graph, MGraph_Printf* pFunc);

#endif

MGraph.c

#include <malloc.h>

#include <stdio.h>

#include "MGraph.h"

#include "LinkQueue.h"

typedef struct _tag_MGraph

{

    int count;

    MVertex** v;

    int** matrix;

} TMGraph;

static void recursive_dfs(TMGraph* graph, int v, int visited[], MGraph_Printf* pFunc)

{

    int i = 0;

   

    pFunc(graph->v[v]);

   

    visited[v] = 1;

   

    printf(", ");

   

    for(i=0; i<graph->count; i++)

    {

        if( (graph->matrix[v][i] != 0) && !visited[i] )

        {

            recursive_dfs(graph, i, visited, pFunc);

        }

    }

}

static void bfs(TMGraph* graph, int v, int visited[], MGraph_Printf* pFunc)

{

    LinkQueue* queue = LinkQueue_Create();

   

    if( queue != NULL )

    {

        LinkQueue_Append(queue, graph->v + v);

       

        visited[v] = 1;

       

        while( LinkQueue_Length(queue) > 0 )

        {

            int i = 0;

           

            v = (MVertex**)LinkQueue_Retrieve(queue) - graph->v;

           

            pFunc(graph->v[v]);

           

            printf(", ");

           

            for(i=0; i<graph->count; i++)

            {

                if( (graph->matrix[v][i] != 0) && !visited[i] )

                {

                    LinkQueue_Append(queue, graph->v + i);

                   

                    visited[i] = 1;

                }

            }

        }

    }

   

    LinkQueue_Destroy(queue);

}

MGraph* MGraph_Create(MVertex** v, int n)  // O(n)

{

    TMGraph* ret = NULL;

   

    if( (v != NULL ) && (n > 0) )

    {

        ret = (TMGraph*)malloc(sizeof(TMGraph));

       

        if( ret != NULL )

        {

            int* p = NULL;

           

            ret->count = n;

           

            ret->v = (MVertex**)malloc(sizeof(MVertex*) * n);

           

            ret->matrix = (int**)malloc(sizeof(int*) * n);

           

            p = (int*)calloc(n * n, sizeof(int));

           

            if( (ret->v != NULL) && (ret->matrix != NULL) && (p != NULL) )

            {

                int i = 0;

               

                for(i=0; i<n; i++)

                {

                    ret->v[i] = v[i];

                    ret->matrix[i] = p + i * n;

                }

            }

            else

            {

                free(p);

                free(ret->matrix);

                free(ret->v);

                free(ret);

               

                ret = NULL;

            }

        }

    }

   

    return ret;

}

void MGraph_Destroy(MGraph* graph) // O(1)

{

    TMGraph* tGraph = (TMGraph*)graph;

   

    if( tGraph != NULL )

    {

        free(tGraph->v);

        free(tGraph->matrix[0]);

        free(tGraph->matrix);

        free(tGraph);

    }

}

void MGraph_Clear(MGraph* graph) // O(n*n)

{

    TMGraph* tGraph = (TMGraph*)graph;

   

    if( tGraph != NULL )

    {

        int i = 0;

        int j = 0;

       

        for(i=0; i<tGraph->count; i++)

        {

            for(j=0; j<tGraph->count; j++)

            {

                tGraph->matrix[i][j] = 0;

            }

        }

    }

}

int MGraph_AddEdge(MGraph* graph, int v1, int v2, int w) // O(1)

{

    TMGraph* tGraph = (TMGraph*)graph;

    int ret = (tGraph != NULL);

   

    ret = ret && (0 <= v1) && (v1 < tGraph->count);

    ret = ret && (0 <= v2) && (v2 < tGraph->count);

    ret = ret && (0 <= w);

   

    if( ret )

    {

        tGraph->matrix[v1][v2] = w;

    }

   

    return ret;

}

int MGraph_RemoveEdge(MGraph* graph, int v1, int v2) // O(1)

{

    int ret = MGraph_GetEdge(graph, v1, v2);

   

    if( ret != 0 )

    {

        ((TMGraph*)graph)->matrix[v1][v2] = 0;

    }

   

    return ret;

}

int MGraph_GetEdge(MGraph* graph, int v1, int v2) // O(1)

{

    TMGraph* tGraph = (TMGraph*)graph;

    int condition = (tGraph != NULL);

    int ret = 0;

   

    condition = condition && (0 <= v1) && (v1 < tGraph->count);

    condition = condition && (0 <= v2) && (v2 < tGraph->count);

   

    if( condition )

    {

        ret = tGraph->matrix[v1][v2];

    }

   

    return ret;

}

int MGraph_TD(MGraph* graph, int v) // O(n)

{

    TMGraph* tGraph = (TMGraph*)graph;

    int condition = (tGraph != NULL);

    int ret = 0;

   

    condition = condition && (0 <= v) && (v < tGraph->count);

   

    if( condition )

    {

        int i = 0;

       

        for(i=0; i<tGraph->count; i++)

        {

            if( tGraph->matrix[v][i] != 0 )

            {

                ret++;

            }

           

            if( tGraph->matrix[i][v] != 0 )

            {

                ret++;

            }

        }

    }

   

    return ret;

}

int MGraph_VertexCount(MGraph* graph) // O(1)

{

    TMGraph* tGraph = (TMGraph*)graph;

    int ret = 0;

   

    if( tGraph != NULL )

    {

        ret = tGraph->count;

    }

   

    return ret;

}

int MGraph_EdgeCount(MGraph* graph) // O(n*n)

{

    TMGraph* tGraph = (TMGraph*)graph;

    int ret = 0;

   

    if( tGraph != NULL )

    {

        int i = 0;

        int j = 0;

       

        for(i=0; i<tGraph->count; i++)

        {

            for(j=0; j<tGraph->count; j++)

            {

                if( tGraph->matrix[i][j] != 0 )

                {

                    ret++;

                }

            }

        }

    }

   

    return ret;

}

void MGraph_DFS(MGraph* graph, int v, MGraph_Printf* pFunc)

{

    TMGraph* tGraph = (TMGraph*)graph;

    int* visited = NULL;

    int condition = (tGraph != NULL);

   

    condition = condition && (0 <= v) && (v < tGraph->count);

    condition = condition && (pFunc != NULL);

    condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL);

   

    if( condition )

    {

        int i = 0;

       

        recursive_dfs(tGraph, v, visited, pFunc);

       

        for(i=0; i<tGraph->count; i++)

        {

            if( !visited[i] )

            {

                recursive_dfs(tGraph, i, visited, pFunc);

            }

        }

       

        printf("\n");

    }

   

    free(visited);

}

void MGraph_BFS(MGraph* graph, int v, MGraph_Printf* pFunc)

{

    TMGraph* tGraph = (TMGraph*)graph;

    int* visited = NULL;

    int condition = (tGraph != NULL);

   

    condition = condition && (0 <= v) && (v < tGraph->count);

    condition = condition && (pFunc != NULL);

    condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL);

   

    if( condition )

    {

        int i = 0;

       

        bfs(tGraph, v, visited, pFunc);

       

        for(i=0; i<tGraph->count; i++)

        {

            if( !visited[i] )

            {

                bfs(tGraph, i, visited, pFunc);

            }

        }

       

        printf("\n");

    }

   

    free(visited);

}

void MGraph_Display(MGraph* graph, MGraph_Printf* pFunc) // O(n*n)

{

    TMGraph* tGraph = (TMGraph*)graph;

   

    if( (tGraph != NULL) && (pFunc != NULL) )

    {

        int i = 0;

        int j = 0;

       

        for(i=0; i<tGraph->count; i++)

        {

            printf("%d:", i);

            pFunc(tGraph->v[i]);

            printf(" ");

        }

       

        printf("\n");

       

        for(i=0; i<tGraph->count; i++)

        {

            for(j=0; j<tGraph->count; j++)

            {

                if( tGraph->matrix[i][j] != 0 )

                {

                    printf("<");

                    pFunc(tGraph->v[i]);

                    printf(", ");

                    pFunc(tGraph->v[j]);

                    printf(", %d", tGraph->matrix[i][j]);

                    printf(">");

                    printf(" ");

                }

            }

        }

       

        printf("\n");

    }

}

LinkQueue.h

LinkQueue.c

小结:

邻接矩阵法

邻接链表法

优点:直观,容易实现。

缺点:当顶点数较多,而边数较少是浪费时间和空间。

优点:有效利用空间,非常适合边数较少的图。

缺点:实现相对复杂,不容易查找两个顶点之间的权值。

邻接矩阵法和邻接链表法的选择不是绝对的,需要根据实际情况综合考虑。

猜你喜欢

转载自www.cnblogs.com/free-1122/p/11336068.html