图
G = V, E
图由多个点和边构成
V:顶点的集合,不能为空
E:边的集合,可以为空
图分为两种
无向图:(v1, v2) == (v2, v1)
V(G1) = {v1, v2, v3, v4} -- 一维数组
E(G1) = {(v1, v2), (v1, v3), (v1, v4), (v2, v3), (v2, v4), (v3, v4)} -- 二维矩阵
有向图:<v1, v2> != <v2, v1>
V(G2) = {v1, v2, v3, v4} -- 一维数组
E(G2) = {<v1, v2>, <v2, v3>, <v3, v4>, <v4, v1>, <v2, v4>, <v1, v3> } -- 二维矩阵
完全图
图中任意两点都有一条边
无向完全图:
n个顶点 --> n(n-1)/2条边
v1 -- v2
| \ / |
| |
v4 -- v3
有向完全图:
n个顶点 --> n(n-1)条边
网(带权图)
带权重的图叫做网
2
v1 -- v2
5 | | 4
| |
v4 -- v3
3
邻接点
顶点和顶点的关系:
v1 -- v2 无向
v1 → v2 有向
v1和v2是邻接点
关联
边和顶点间的关系:
v1 → v2
边→:关联v1和v2
顶点的度
与该顶点相关联的边的数目
v1 → v2
↓ ↘
v4 v3
顶点v1的度为3
所有顶点度数之和 == 边的两倍 (重复统计)
入度:以v1为终点,进入v1的,有向边的条数
出度:以v1为起点,走出v1的,有向边的条数
路径
一个个顶点构成的序列:
s → v1 → v2 → t
路径的长度是边的数目
回环路径
第一个顶点和最后一个顶点相同
子图
从原图中选取若干条边和顶点
生成子图
从图中选出 所有 的顶点和 任意 条边
连通图
vi到vj有路径
如果图中任意两个顶点之间都是连通的,则该图为连通图
最大连通子图,再次添加一个顶点,就不连通了
图的存储结构
1.顺序存储
邻接矩阵adjacency_matrix表示顶点之间的关系
缺点:迅速判断两个节点之间是否有边,方便计算各个顶点之间的度
优点:不方便图中顶点的增加个删除,不方便访问各个邻接点
需要两个数组来储存图
一维数组储存顶点信息
二维数组储存顶点和顶点之间的邻接关系即边 notice:
a -- b
| / | 4个顶点,5条边
d -- c
vex[] = a b c d -- 储存顶点的信息,一维数组
储存顶点和顶点之间的邻接关系01,二维矩阵:
a b c d
Edge[i][j] = a 0 1 0 1
b 1 0 1 1
c 0 1 0 1
d 1 1 1 0
1.对称阵 Edge[i][j] == Edge[j][i]
2.第i行或第i列所有非0元素的个数 == 顶点的度
b
↗ ↖
a → c 4个顶点,5条边
↓ ↙ ↓
e ← d
Vex[] = a b c d e
a b c d e
Egde[i][j] = a 0 1 1 0 1
b 0 0 0 0 0
c 0 1 0 1 1
d 0 0 0 0 1
e 0 0 0 0 0
1.不一定是对称
2.第i行非零元素的个数 == 第i个顶点的出度
3.第i列非零元素的个数 == 第i个顶点的入度
2.链式存储
邻接表
#include "undirected_mat.h"
int main()
{
struct AMG_Graph* ud_graph;
ud_graph = Create_AMG_Graph();
Show_AMG_Graph(ud_graph);
return 0;
}
undirected_mat.cpp
#include <iostream>
using namespace std;
#include "undirected_mat.h"
// adjacency_matrix_
struct AMG_Graph* Create_AMG_Graph()
{
int i, j;
char u, v;
struct AMG_Graph* graph;
// 申请内存空间,结构体多大申请多大,强制类型转换
graph = (struct AMG_Graph *)malloc(sizeof(struct AMG_Graph));
cout << "请输入顶点的个数: ";
cin >> graph->vex_num;
cout << "请输入边的个数: ";
cin >> graph->edge_num;
cout << "请输入顶点信息: " << endl;
for(i = 0; i < graph->vex_num; i++)
{
// 一维数组,顶点信息:abcd...,对应索引0123
cin >> graph->Vex[i];
}
// o(n²)
for(i = 0; i < graph->vex_num; i++)
{
for(j = 0; j < graph->vex_num; j++)
{
// 初始化为0
graph->Edge[i][j] = 0;
}
}
while(graph->edge_num--)
{
cout << "请输入通过边连接起来的顶点:" << endl;
cin >> u;
cin >> v;
// 到graph中找到字符u,所对应的索引
i = search_vex(graph, u);
j = search_vex(graph, v);
if(i != -1 && j != -1)
// 无向图为对称阵
graph->Edge[i][j] = graph->Edge[j][i] = 1;
else
{
cout << "你输入的顶点信息是错的,请再次输入" << endl;
graph->edge_num++;
}
}
return graph;
}
int search_vex(struct AMG_Graph* graph, char c)
{
int i;
// 遍历所有顶点
for(i = 0; i < graph->vex_num; i++)
{
// 如果找到该顶点,则返回其索引
if(c == graph->Vex[i])
return i;
}
return -1;
}
void Show_AMG_Graph(struct AMG_Graph * graph)
{
int i,j;
cout << "显示顶点信息:"<< endl;
// o(n)
for(i = 0; i < graph->vex_num; i++)
cout << graph->Vex[i] << "\t";
cout << endl;
cout << "显示邻接矩阵:" << endl;
// o(n²)
for(i = 0; i < graph->vex_num; i++)
{
for(j = 0; j < graph->vex_num; j++)
{
cout << graph->Edge[i][j] << "\t";
}
cout << endl;
}
}
undirected_mat.h
#ifndef __undirected_mat_h__
#define __undirected_mat_h__
#define MAX 100
struct AMG_Graph
{
// 顶点的个数,边的个数
int vex_num, edge_num;
// 储存顶点的信息,一维数组
char Vex[MAX];
// 储存顶点和顶点之间的邻接关系,二维矩阵
int Edge[MAX][MAX];
};
struct AMG_Graph* Create_AMG_Graph();
void Show_AMG_Graph(struct AMG_Graph * graph);
int search_vex(struct AMG_Graph* graph, char c);
#endif