数据--第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

小结:


邻接矩阵法


邻接链表法


优点:直观,容易实现。

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


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

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

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

原文地址:https://www.cnblogs.com/free-1122/p/11336068.html

时间: 2024-10-13 16:33:12

数据--第41棵 - 图的存储结构的相关文章

(转)数据结构之图(存储结构、遍历)

一.图的存储结构 1.1 邻接矩阵 图的邻接矩阵存储方式是用两个数组来表示图.一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息. 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 看一个实例,下图左就是一个无向图. 从上面可以看出,无向图的边数组是一个对称矩阵.所谓对称矩阵就是n阶矩阵的元满足aij = aji.即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的. 从这个矩阵中,很容易知道图中的信息. (1)要判断任意两顶点是否有

图的存储结构及遍历

一.图的存储结构 1.1 邻接矩阵 图的邻接矩阵存储方式是用两个数组来表示图.一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息. 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 看一个实例,下图左就是一个无向图. 从上面可以看出,无向图的边数组是一个对称矩阵.所谓对称矩阵就是n阶矩阵的元满足aij = aji.即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的. 从这个矩阵中,很容易知道图中的信息. (1)要判断任意两顶点是否有

java 数据结构 图中使用的一些常用算法 图的存储结构 邻接矩阵:图的邻接矩阵存储方式是用两个数组来标示图。一个一位数组存储图顶点的信息,一个二维数组(称为邻接矩阵)存储图中边或者弧的信息。 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 实例如下,左图是一个无向图。右图是邻接矩阵表示:

以下内容主要来自大话数据结构之中,部分内容参考互联网中其他前辈的博客. 图的定义 图是由顶点的有穷非空集合和顶点之间边的集合组成,通过表示为G(V,E),其中,G标示一个图,V是图G中顶点的集合,E是图G中边的集合. 无边图:若顶点Vi到Vj之间的边没有方向,则称这条边为无项边(Edge),用序偶对(Vi,Vj)标示. 对于下图无向图G1来说,G1=(V1, {E1}),其中顶点集合V1={A,B,C,D}:边集合E1={(A,B),(B,C),(C,D),(D,A),(A,C)}: 有向图:若

数据结构之图(一)图的存储结构

图的存储结构相对于线性表和树来说更为复杂,因为图中的顶点具有相对概念,没有固定的位置.那我们怎么存储图的数据结构呢?我们知道,图是由(V, E)来表示的,对于无向图来说,其中 V = (v0, v1, ... , vn),E = { (vi,vj) (0 <=  i, j <=  n且i 不等于j)},对于有向图,E = { < vi,vj > (0 <=  i, j <=  n且i 不等于j)}.V是顶点的集合,E是边的集合.所以我们只要把顶点和边的集合储存起来,那么

数据结构 - 图的存储结构

图的抽象数据类型定义 图是一种数据结构,加上一组基本操作就构成了图的抽象数据类型. 图的抽象数据类型定义如下: ADT Graph{ 数据对象V:具有相同特性的数据元素的集合,称为顶点集. 数据关系R:R={VR} VR={<v,w>|<v,w>| v,w?V∧p(v,w) ,<v,w>表示 从v到w的弧,P(v,w)定义了弧<v,w>的信息 } 基本操作P: Create_Graph() : 图的创建操作. 初始条件:无. 操作结果:生成一个没有顶点的空图

《大话数据结构》笔记(7-2)--图:存储结构

第七章  图 图的存储结构 图不能用简单的顺序存储结构来表示. 而多重链表的方式,即以一个数据域和多个指针域组成的结点表示图中的一个顶点,尽管可以实现图结构,但是会有问题,比如若各个顶点的度数相差很大,按度数最大的顶点设计结点结构会造成很多存储单元的浪费,而若按每个顶点自己的度数设计不同的顶点结构,又带来操作的不便. 对于图来说,如何对它实现物理存储是个难题.图有以下五种不同的存储结构. 邻接矩阵 图的邻接矩阵(Adjacency Matrix)存储方式使用过两个数组来表示图.一个一维数组存储图

图的存储结构(邻接矩阵)

图的存储结构(邻接矩阵) 让编程改变世界 Change the world by program 图的存储结构 图的存储结构相比较线性表与树来说就复杂很多. 我们回顾下,对于线性表来说,是一对一的关系,所以用数组或者链表均可简单存放.树结构是一对多的关系,所以我们要将数组和链表的特性结合在一起才能更好的存放. 那么我们的图,是多对多的情况,另外图上的任何一个顶点都可以被看作是第一个顶点,任一顶点的邻接点之间也不存在次序关系. 我们仔细观察以下几张图,然后深刻领悟一下: 因为任意两个顶点之间都可能

数据结构(五)图---图的存储结构5种

一:图的抽象数据类型 ADT 图(Graph) Data 顶点的有穷非空集合和边的集合 Operation CreateGraph(*G,V,VR):按照顶点集V和边弧集VR的定义构造图G DestroyGraph(*G):图G存在则销毁 LocateVex(G,u):若图G中存在顶点u,则返回图中位置 GetVex(G,v):返回图中顶点v的值 PutVex(G,v,value):将图G中顶点v赋值给value FirstAdjVex(G,*v):返回顶点v的一个邻接顶点,若顶点在G中无邻接顶

【algo&amp;ds】5.图及其存储结构、遍历

1.什么是图 图表示"多对多"的关系 包含 一组顶点:通常用 V(Vertex)表示顶点集合 一组边:通常用 E(Edge)表示边的集合 边是顶点对:(v,w)∈ E,其中 v,w ∈ V ,v-w 有向边 <v,w> 表示从 v 指向 w 的边(单行线) v→w 不考虑重边和自回路 常见术语 无向图:图中所有的边无所谓方向 有向图:图中的边可能是双向,也可能是单向的,方向是很重要的 权值:给图中每条边赋予的值,可能有各种各样的现实意义 网络:带权值的图 邻接点:有边直接相