图是一种常用的数据结构,可用于表示对象之间的存在的多对多关系
图的定义和术语
完全图
稀疏图(Sparse Graph)和稠密图(Dense Gaph)
权
某些图的边具有与它相关的数, 称之为权。这种带权图叫做网络。
顶点的度(degree)
路径(path)
连通图(Connected Graph)
连通子图和连通分量(Connected Component)
极小连通子图和生成树(Spanning Tree)
图的存储结构
邻接矩阵(Adjacency Matrix)
带权图中无连通性的邻接矩阵表示:无穷大
根据邻接矩阵计算顶点的度:
在有向图中, 统计第 i 行 1 的个数可得顶点 i 的出度,统计第 j 列 1 的个数可得顶点 j 的入度。
在无向图中, 统计第 i 行 (列) 1 的个数可得顶点i 的度。
图的邻接矩阵实现
class Graphm:public Graph {
private:
int numVertex, numEdge; //顶点数和边数
int **matrix; // Pointer to adjacency matrix
int *mark;
// Pointer to mark array,指向标记数组的指针,用于遍历
public:
Graphm(int numVert) // Constructor
{ Init(numVert); } ~Graphm() { // Destructor
cout<<"gramat delete";
delete [] mark; // Return dynamically allocated memory
for (int i=0; i<numVertex; i++)
delete [] matrix[i];
delete [] matrix; }
void Init(int n) { // Initialize the graph
int i;
numVertex = n;
numEdge = 0;
mark = new int[n]; // Initialize mark array
for (i=0; i<numVertex; i++)
mark[i] = UNVISITED;
matrix = (int**) new int*[numVertex]; // Make matrix
for (i=0; i<numVertex; i++)
matrix[i] = new int[numVertex];
for (i=0; i< numVertex; i++) // Initialize to 0 weights
for (int j=0; j<numVertex; j++)
matrix[i][j] = 0;
}
int n() { return numVertex; } // 顶点数
int e() { return numEdge; } // 边数
// 返回顶点v的第一个邻居
int first(int v) {
for (int i=0; i<numVertex; i++)
if (matrix[v][i] != 0) return i;
return numVertex; // 无邻居
}
// 返回顶点v在w之后的下一个邻居
int next(int v, int w) {
for(int i=w+1; i<numVertex; i++)
if (matrix[v][i] != 0)
return i;
return numVertex; //顶点v在w后无邻居 }
void setEdge(int v1, int v2, int wt) {
// 设置 (v1, v2) 边的权值为 wt
Assert(wt>0,
"Illegal weight value");
if (matrix[v1][v2] == 0) //若原来没有该边
numEdge++;
matrix[v1][v2] = wt;
}
void delEdge(int v1, int v2) {
// 删除边 (v1, v2)
if (matrix[v1][v2] != 0){
numEdge--;
matrix[v1][v2] = 0;
}
}
bool isEdge(int i, int j) // 顶点 i到顶点j有边吗?
{ return matrix[i][j] != 0; }
int weight(int v1, int v2) { return matrix[v1][v2];
}
int getMark(int v) { return mark[v]; }
void setMark(int v, int val) { mark[v] = val; }
邻接表
带权图的边结点中保存该边上的权值 cost。
顶点 i 的边链表的表头指针 adj 在顶点表的下标为 i 的顶点记录中,该记录还保存了该顶点的其它信息。
在邻接表的边链表中,各个边结点的链入顺序任意, 视边结点输入次序而定。
设图中有 n 个顶点,e 条边,则用邻接表表示无向图 时,需要 n 个顶点结点,2e 个边结点;用邻接表表示有向图时,若不考虑逆邻接表,只需 n 个顶点结点, e 个边结点
图的邻接表实现
数据类型定义
typedef struct __EdgeNode {
int adjvertex;
__EdgeNode *next;
int weight;
} EdgeNode;
typedef struct __ALGNode {
VertexType name;
EdgeNode *first;
} ALGNode;
typedef struct __ALGraph {
ALGNode vertex[MAXVERTEX];
int edges, vertices;
} ALGraph;
无向无权图的邻接表实现代码:
无向有权,有向无权,有向有权图的创建方法和此方法类似,只需改动weight,和新建节点个数即可
void Creat_unALGraph_unweighted(ALGraph *G) {
//初始化点和边个数
printf("Please input the number of vertices:");
scanf(" %d", &G->vertices);
printf("Please input the number of edges:");
scanf(" %d", &G->edges);
//输入各个顶点的名字
printf("Please input the name of vertices(just like A B C):");
for (int i = 0; i < G->vertices; ++i) {
scanf(" %c", &G->vertex[i].name);
G->vertex[i].first = NULL;
}
char v1, v2; //一条边的顶点
int index_v1, index_v2; //边的顶点的下标
for (int i = 0; i < G->edges; ++i) {
printf("(for %d)Please input the edge(just like A B):", i + 1);
scanf(" %c %c", &v1, &v2);
index_v1 = Locate_vertex(G, v1);
index_v2 = Locate_vertex(G, v2);
//创造新节点1
EdgeNode *pnew1 = (EdgeNode *)malloc(sizeof(EdgeNode));
pnew1->adjvertex = index_v2;
//头插法
pnew1->next = G->vertex[index_v1].first;
G->vertex[index_v1].first = pnew1;
//创造新节点2
EdgeNode *pnew2 = (EdgeNode *)malloc(sizeof(EdgeNode));
pnew2->adjvertex = index_v1;
//头插法
pnew2->next = G->vertex[index_v2].first;
G->vertex[index_v2].first = pnew2;
}
}
测试代码
#include "ALGraph.h"
int main(void) {
ALGraph G;
Creat_unALGraph_unweighted(&G);
print_ALG_unweighted(&G);
system("pause");
return 0;
}
//
/*
5 6
A B C D E
A B
A D
B C
D C
C E
B E
----------------------
A:A--D A--B
B:B--E B--C B--A
C:C--E C--D C--B
D:D--C D--A
E:E--B E--C
*/