您的位置:首页 > 理论基础 > 数据结构算法

数据结构--图的定义和存储结构

2015-06-23 19:06 573 查看
图的定义

图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成。注意:在图结构中,不允许没有顶点,在定义中,如果V是顶点的集合,则强调了顶点集合V的有穷非空。

在图中,若不存在顶点到其自身的边,且同一条边不重复出现,则称这样的图为简单图。

图的存储结构

邻接矩阵

考虑到图是由顶点和边或者弧两部分组成的。合在一起比较困难,那就自然地考虑到分两个结构来分别存储。顶点不分大小、主次,所以用一个一位数组来存储是很不错的选择。而边或者弧是顶点与顶点之间的关系,一维搞不定,那就考虑用一个二维数组来存储。



对于带权值的图,可以令不可达的边的权值为无穷大。利用这个无穷大代表两个顶点不可达。

邻接矩阵结构代码

//为了简单,默认顶点为int类型,也就是v0,v1,v2等的那个下标
//权值为int类型

#define MAXVEX 100
#define INF 65535

typedef struct
{
int vexs[MAXVEX];
int arc[MAXVEX][MAXVEX];

int numVertexes, numEdges;
}MGraph;


  

无向图的创建代码:

void CreateMGraph(MGraph *G)
{
//k为循环变量
int k = 0;
//i,j代表顶点的下标
int i = 0;
int j = 0;

printf("读取顶点和边的数目...\n");
scanf("%d,%d", &G->numVertexes, &G->numEdges);

//输入顶点信息
printf("读取顶点信息...\n");
for(k = 0; k < G->numVertexes; k++)
{
scanf("%d", &G->vexs[k]);
}

//初始化所有的边为无穷大
for(i = 0; i < G->numVertexes; i++)
{
for(j = 0; j < G->numVertexes; j++)
{
G->arc[i][j] = INF;
}
}//for

int weight = 0;
//获取权值的输入值
printf("读取边(vi,vj)中两个顶点的下表i、j和对应的权值...\n");
for(k = 0; k < G->numEdges; k++)
{
scanf("%d,%d,%d", &i, &j, &weight);

G->arc[i][j] = weight;
G->arc[j][i] = weight;
}//for

}//CreateMGraph()


  无向图的边的二维数组是一个对称矩阵,有向图的创建更加简单。

测试代码:

void main(void)
{
freopen("in.txt", "r", stdin);
MGraph mGraph;
MGraph *pMGraph = &mGraph;
CreateMGraph(pMGraph);

fclose(stdin);

return;
}


试验数据:

//in.txt
4,5
0
1
2
3
0,1,10
0,2,2
0,3,7
1,2,8
2,3,5


邻接表

回忆在树的存储结构中,降到了一种孩子表示法,将这种数组与链表相结合的存储方法称为邻接表。



注意上图的数组称为顶点表,链表为边表结点。

对于有向图,其实更加简单,但是有向图的每一个顶点分为入度和出度。





邻接表结构代码:

#define MAXVEX 100

typedef struct EdgeNode
{
int adjvex;
int weight;//边的权重,用int表示
struct EdgeNode *next;
}EdgeNode;

typedef struct VertexNode
{
int data;
EdgeNode *firstEdge;
}AdjList;

typedef struct
{
AdjList adjList[MAXVEX];
int numVertexs;
int numEdges;
}AdjGraph;


  

邻接表创建有向图代码:

void CreateAdjGraph(AdjGraph *G)
{
//统一规定,k用作循环变量
int k = 0;

printf("读取顶点和边数目...\n");
scanf("%d%d", &G->numVertexs, &G->numEdges);

printf("读取顶点...\n");
for(k = 0; k < G->numVertexs; k++)
{
scanf("%d", &G->adjList[k].data);
G->adjList[k].firstEdge = NULL;
}

printf("读取边信息...\n");
//i,j用作表示顶点的下表,weight表示边的权重
int i = 0;
int j = 0;
int weight = 0;

for(k = 0; k < G->numEdges; k++)
{
scanf("%d%d%d", &i, &j, &weight);

EdgeNode *pEdgeNode = (EdgeNode*)malloc(sizeof(EdgeNode));
pEdgeNode->adjvex = j;
pEdgeNode->weight = weight;
pEdgeNode->next = NULL;

//采用头插法,将这个边节点插入
pEdgeNode->next = G->adjList[i].firstEdge;
G->adjList[i].firstEdge = pEdgeNode;

/*无向图插入边信息

//对于无向图,这里要再次插入
EdgeNode *pEdgeNode = (EdgeNode*)malloc(sizeof(EdgeNode));
pEdgeNode->adjvex = i;
pEdgeNode->weight = weight;
pEdgeNode->next = NULL;

//采用头插法,将这个边节点插入
pEdgeNode->next = G->adjList[j].firstEdge;
G->adjList[j].firstEdge = pEdgeNode;
*/

}

}//CreateAdjGraph


  在插入边表结点的时候,采用头插法更加简单一些。

测试代码:

void main(void)
{
freopen("in.txt", "r", stdin);

AdjGraph adjGraph;
AdjGraph *pAdjGraph = &adjGraph;
CreateAdjGraph(pAdjGraph);

fclose(stdin);
}


  

测试数据:

//in.txt
10 19
0 1 2 3 4 5 6 7 8 9
0 1 4
0 2 1
0 3 3
2 3 1
1 4 9
1 5 8
2 4 6
2 5 7
2 6 8
3 5 4
3 6 7
4 7 5
4 8 6
5 7 8
5 8 6
6 7 6
6 8 5
7 9 7
8 9 3
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: