图(一)
简单小知识
弧头和弧尾
在有向图中,箭头指向的一端被称为弧头,箭头发出的一端被称为弧尾。
入度和出度
在有向图中,一个顶点有几个发出箭头它就有几个出度,有几个指向它的箭头它就有几个入度,而顶点的度等于入度数和出度数的和。
(v1,v2)和<v1,v2>
(v1,v2)指的是无向图中v1和v2的关系,证明v1和v2是邻接点(若某两个顶点之间有边或者弧,则这两个顶点就为邻接点),而<v1,v2>指的是有向图中v1和v2的关系,证明v1、v2之间有一个箭头,并且是v1指向v2。
图和网
带权的叫网,不带的叫图。
根据特征分图
完全图:每个顶点(除自身外)与图中其他的顶点都有关系,没有方向的叫完全图,而有方向的叫有向完全图。特点: 具有n个顶点的完全图,边的数量为n(n-1)/2,有向完全图弧的数量为n(n-1)。
稀疏图、稠密图:边或者弧多的图叫稠密图,反之叫稀疏图。判断条件为:e<nlogn,其中 e 表示图中边(或弧)的数量,n 表示图中顶点的数量。如果式子成立,则为稀疏图;反之为稠密图。
连通图
无向图中,若任意两个顶点之间都至少存在一条路径,则这个无向图成为连通图。若无向图不是连通图,而它的某个子图符合连通的性质,则称这个子图为连通分量(这里的子图指最大的连通子图)。若整个无向图都是连通图,则不可能存在连通分量。
在有向图中,若任意两个顶点,都满足从一个顶点a到另一个顶点b和b到a连通,即至少有一条路径,则这个有向图为强连通图,强连通分量与连通分量定义相同。
连通图的生成树
定义:
1.包含连通图的所有顶点
2.任意两个顶点之间有且只有一条通路
生成树 边的数量=顶点数-1.
非连通图的生成森林
非连通图可以分解为多个连通分量,而每个连通分量会有一个生成树,所以所有生成树构成了非连通图的生成森林。
图的顺序存储结构
利用数组,邻接矩阵来解决问题,一维数组记录数据,二维数组(邻接矩阵)记录关系。。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define max_NUM 20//顶点个数
#define VRType int//顶点之间关系变量
#define InfoType char//边或者弧之间额外信息指针变量
#define VertexType int//顶点数据
typedef enum{DG,DN,UDG,UDN}Graphkind;//枚举的类型
typedef struct
{
VRType adj;//图:1相邻0否 网:权值
InfoType* info;//边或者弧之间指针变量
}AreCell,AdjMatrix[max_NUM][max_NUM];
typedef struct
{
VertexType vexs[max_NUM];//顶点数据
AdjMatrix arcs;//二维数组记录顶点之间关系
int vexnum, arcnum;//顶点数 边数
Graphkind kind;//图的种类(枚举类型)
}MGraph;
//根据顶点数据,判断顶点在二维数组中的位置
int LocateVex(MGraph* G, VertexType v)
{
int i = 0;
for (; i < G->vexnum; i++)
{
if (G->vexs[i] == v)
{
break;
}
}
if (i > G->vexnum)
{
printf("nu such vertex\n");
return -1;
}
return i;
}
//有向图
void CreateDG(MGraph* G)
{
scanf("%d %d", &G->vexnum, &G->arcnum);
for (int i = 0; i < G->vexnum; i++)
{
scanf("%d", &G->vexs[i]);
}
for (int i = 0; i < G->vexnum; i++)
{
for (int j = 0; j < G->vexnum; j++)
{
G->arcs[i][j].adj = 0;
G->arcs[i][j].info = NULL;
}
}
for (int i = 0; i < G->arcnum; i++)
{
int v1, v2;
scanf("%d %d", &v1, &v2);//边|弧的头与尾
int n = (LocateVex(G, v1));
int m = (LocateVex(G, v2));
if (n == -1 || m == -1)
{
printf("no such vertex\n");
return;
}
G->arcs[n][m].adj = 1;
}
}
//无向图
void CreateDN(MGraph* G)
{
scanf("%d %d", &G->vexnum, &G->arcnum);
for (int i = 0; i < G->vexnum; i++)
{
scanf("%d", &G->vexs[i]);
}
for (int i = 0; i < G->vexnum; i++)
{
for (int j = 0; j < G->vexnum; j++)
{
G->arcs[i][j].adj = 0;
G->arcs[i][j].info = NULL;
}
}
for (int i = 0; i < G->arcnum; i++)
{
int v1, v2;
scanf("%d %d", &v1, &v2);
int n = LocateVex(G, v1);
int m = LocateVex(G, v2);
if (m == -1 || n == -1)
{
printf("no such vertex\n");
return;
}
G->arcs[n][m].adj = 1;
G->arcs[m][n].adj = 1;//无向图二阶矩阵主对角线对称
}
}
//有向网
void CreateUDG(MGraph* G)
{
scanf("%d %d", &G->vexnum, &G->arcnum);
for (int i = 0; i < G->vexnum; i++)
{
scanf("%d", &G->vexs[i]);
}
for (int i = 0; i < G->vexnum; i++)
{
for (int j = 0; j < G->vexnum; j++)
{
G->arcs[i][j].adj = 0;
G->arcs[i][j].info = NULL;
}
}
for (int i = 0; i < G->arcnum; i++)
{
int v1, v2, w;
scanf("%d %d %d", &v1, &v2, &w);
int n = (LocateVex(G, v1));
int m = (LocateVex(G, v2));
if (n == -1 || m == -1)
{
printf("no such vertex\n");
return;
}
G->arcs[n][m].adj = w;
}
}
//无向网
void CreateUDN(MGraph* G)
{
scanf("%d %d", &G->vexnum, &G->arcnum);
for (int i = 0; i < G->vexnum; i++)
{
scanf("%d", &G->vexs[i]);
}
for (int i = 0; i < G->vexnum; i++)
{
for (int j = 0; j < G->vexnum; j++)
{
G->arcs[i][j].adj = 0;
G->arcs[i][j].info = NULL;
}
}
for (int i = 0; i < G->arcnum; i++)
{
int v1, v2, w;
scanf("%d %d %d", &v1, &v2, &w);
int n = LocateVex(G, v1);
int m = LocateVex(G, v2);
if (m == -1 || n == -1)
{
printf("no such vertex\n");
return;
}
G->arcs[n][m].adj = w;
G->arcs[m][n].adj = w;
}
}
//选择图的类型
void CreateGraph(MGraph* G)
{
scanf("%d", &G->kind);
switch (G->kind)
{
case DG:
return CreateDG(G);
break;
case DN:
return CreateDN(G);
break;
case UDG:
return CreateUDG(G);
break;
case UDN:
return CreateUDN(G);
break;
defalut:
break;
}
}
//输出
void PrintGraph(MGraph G)//这里的G是结构体变量
{
for (int i = 0; i < G.vexnum; i++)
{
for (int j = 0; j < G.vexnum; j++)
{
printf("%d ", G.arcs[i][j].adj);
}
printf("\n");
}
}
int main()
{
MGraph G;
CreateGraph(&G);
PrintGraph(G);
return 0;
}