在线性表中,数据元素之间是被串起来的,仅有线性关系,每个数据元素只有一个直接前驱和一个直接后继。在树形结构中,数据元素之间有着明显的层次关系,并且每一层上的数据元素可能和下一层中多个元素相关,但只能和上一层中一个元素相关。图是一种较线性表和树更加复杂的数据结构。在图形结构中,结点之间的关系可以是任意的,图中任意两个数据元素之间都可能相关。
1、有向图
若E是有向边(也称弧)的有限集合时,则图G为有向图。弧是顶点的有序对,记为
2、无向图
若E是无向边(简称边)的有限集合时,则图G为无向图。边是顶点的无序对,记为(v, w)或(w,v),因为(v,w)=(w,v), 其中v,w是顶点。可以说顶点w和顶点v互为邻接点。边(v, w)依附于顶点w和v,或者说边(v, w)和顶点v, w相关联。
3、多重图
若图G GG中某两个结点之间的边数多于一条,又允许顶点通过同一条边和自己关联,则G GG为多重图。多重图的定义和简单图是相对的。
4、完全图(也称简单完全图)
对于无向图,∣ E ∣ |E|∣E∣的取值范围是0 00到n ( n − 1 ) / 2 n(n-1)/2n(n−1)/2,有n ( n − 1 ) / 2 n(n -1)/2n(n−1)/2条边的无向图称为完全图,在完全图中任意两个顶点之间都存在边。对于有向图,∣ E ∣ |E|∣E∣的取值范围是0 00到n ( n − 1 ) n(n-1)n(n−1),有n ( n − 1 ) n(n-1)n(n−1)条弧的有向图称为有向完全图,在有向完全图中任意两个顶点之间都存在方向相反的两条弧。
5、连通、连通图和连通分量
在无向图中,若从顶点v vv到顶点w ww有路径存在,则称v vv和w ww是连通的。若图G GG中任意两个顶点都是连通的,则称图G GG为连通图,否则称为非连通图。无向图中的极大连通子图称为连通分量。若一个图有n nn个顶点,并且边数小于n − 1 n-1n−1,则此图必是非连通图。
6、边的权和网
在一个图中,每条边都可以标上具有某种含义的数值,该数值称为该边的权值。这种边上带有权值的图称为带权图,也称网。
7、稠密图、稀疏图
边数很少的图称为稀疏图,反之称为稠密图。稀疏和稠密本身是模糊的概念,稀疏图和稠密图常常是相对而言的。一般当图G满足∣ E ∣ < ∣ V ∣ l o g ∣ V ∣ |E| < |V|log|V|∣E∣<∣V∣log∣V∣时,可以将G GG视为稀疏图。
8、 简单路径、简单回路
在路径序列中,顶点不重复出现的路径称为简单路径。除第一个顶点和最后一个顶点外,其余顶点不重复出现的回路称为简单回路。
9、距离
从顶点u uu出发到顶点v vv的最短路径若存在,则此路径的长度称为从u uu到v vv的距离。若从u uu到v vv根本不存在路径,则记该距离为无穷( ∞ ) 。
10、有向树
一个顶点的入度为0、其余顶点的入度均为1的有向图,称为有向树。
用邻接矩阵实现
邻接矩阵是一种用矩阵表示顶点之间相邻关系的方法。对于一个有n个顶点的图,其邻接矩阵是一个n x n的矩阵,矩阵中的元素表示顶点之间的边的权重。如果两个顶点之间没有边连接,则对应的元素为0。
#include
#include
#define MaxVertexnum 100
typedef int ElemType;
typedef struct graph {
int Nv; // 顶点数
int Ne; // 边数
int Data[MaxVertexnum]; // 存放顶点数据
int Weight[MaxVertexnum][MaxVertexnum]; // 存放权重
} graph, *MGraph;
typedef struct edge {
int V1, V2; // V1到V2
int Weight; // 边的权重
} *Edge;
// 初始化图
void InitGraph(MGraph G, int Vertnex) {
G->Nv = Vertnex; // 顶点数
G->Ne = 0; // 边数为0
for (int i = 0; i < Vertnex; i++) {
for (int j = 0; j < Vertnex; j++) {
G->Weight[i][j] = 0; // 初始化权重为0
}
}
}
// 插入边的权重
void InsertEdge(MGraph G, Edge E) {
G->Weight[E->V1][E->V2] = E->Weight;
G->Weight[E->V2][E->V1] = E->Weight;
}
用邻接表实现
邻接表是一种链式存储结构,用于表示图中的每个顶点及其相邻的顶点。每个顶点都有一个链表,链表中的结点存放与该顶点相邻的顶点信息。
typedef struct node {
int weight; // 存放权重
struct node* next; // 指向下一个边结点
int local; // 该边指向的顶点
} EdgeNode;
typedef struct VNode {
int data; // 顶点数据
node* firstVertnex; // 指向边
} VNode, AdjList[MaxVertexnum];
typedef struct Adjgraph {
int Nv; // 顶点数
int Ne; // 边数
AdjList List; // 邻接表
} AdjMGraph;
// 初始化邻接表
void InitAdjGraph(AdjMGraph* G) {
printf("请输入顶点数和边数(空格分隔)!\n");
scanf("%d %d", &G->Nv, &G->Ne);
printf("请输入顶点数据:\n");
for (int i = 1; i <= G->Nv; i++) {
printf("第%d个顶点数据为:\n", i);
scanf("%d", &G->List[i].data);
G->List[i].firstVertnex = NULL;
}
}
// 创建邻接表
void A(AdjMGraph* G) {
printf("一共有%d条边!\n", G->Ne);
printf("请输入两个顶点以及二者之间的权重(中间用空格分隔):\n");
int W, V, weight;
for (int i = 1; i <= G->Ne; i++) {
scanf("%d %d %d", &W, &V, &weight);
node* p = (node*)malloc(sizeof(node));
p->local = V;
p->weight = weight;
p->next = G->List[W].firstVertnex;
G->List[W].firstVertnex = p;
node* q = (node*)malloc(sizeof(node));
q->local = W;
q->weight = weight;
q->next = G->List[V].firstVertnex;
G->List[V].firstVertnex = q;
}
}