1、图-邻接矩阵
#include <cstdio>
#include <iostream>
// 图的顺序存储
// 邻接矩阵
#define MAXSIZE 100
struct Graph
{
char Vertex[MAXSIZE]; // 顶点集
int Edge[MAXSIZE][MAXSIZE]; // 边集
int cur_v; // 现有顶点数目
int cur_e; // 现有边数目
};
// 建立图
void Create(Graph &G)
{
int i, j, num;
std::cout << "输入顶点的个数:\n";
scanf("%d", &num);
G.cur_v = num;
G.cur_e = 0;
std::cout << "输入顶点的值:\n";
for (i = 0; i < num; ++i)
std::cin >> G.Vertex[i];
printf("输入邻接矩阵:\n");
for (i = 0; i < num; ++i)
{
std::cout << "第" << i + 1 << "行: ";
for (j = 0; j < num; ++j)
{
std::cin >> G.Edge[i][j];
if (G.Edge[i][j] != 0)
++G.cur_e;
}
}
return;
}
int main()
{
int i, j;
Graph G;
Create(G);
printf("顶点: ");
for (i = 0; i < G.cur_v; ++i)
printf("%c ", G.Vertex[i]);
printf("\n边: \n");
for (i = 0; i < G.cur_v; ++i)
{
for (j = 0; j < G.cur_v; ++j)
printf("%d ", G.Edge[i][j]);
printf("\n");
}
return 0;
}
1、图-邻接表
#include <cstdio>
#include <iostream>
#include <vector>
// 图G = (V, {E}); 顶点集 边集
// 邻接表表示该顶点与哪几个顶点之间有边 链表 动态数组
struct Vertex
{
char val; // 顶点的值
std::vector<int> edge; // 该顶点与哪几个顶点有边 // 方便尾插
};
// 图
typedef struct Graph
{
std::vector<Vertex> v;
};
int main()
{
return 0;
}
2、DFS深度优先搜索
#include <cstdio>
#include <iostream>
// 图的顺序存储
// 邻接矩阵
#define MAXSIZE 100
struct Graph
{
char Vertex[MAXSIZE]; // 顶点集
int Edge[MAXSIZE][MAXSIZE]; // 边集
int cur_v; // 现有顶点数目
int cur_e; // 现有边数目
};
// 建立图
void Create(Graph &G)
{
int i, j, num;
std::cout << "输入顶点的个数:\n";
scanf("%d", &num);
G.cur_v = num;
G.cur_e = 0;
std::cout << "输入顶点的值:\n";
for (i = 0; i < num; ++i)
std::cin >> G.Vertex[i];
printf("输入邻接矩阵:\n");
for (i = 0; i < num; ++i)
{
std::cout << "第" << i + 1 << "行: ";
for (j = 0; j < num; ++j)
{
std::cin >> G.Edge[i][j];
if (G.Edge[i][j] != 0)
++G.cur_e;
}
}
return;
}
int visited[MAXSIZE] = {0};
// 深度优先搜索DFS
void DFS(Graph G, int v)
{
// 一条路走到底, 不行就返回上一个位置(返给调用者-上一层递归函数)
// 从v顶点出发, 辅助数组中该顶点的位置 = 1(访问过了该顶点)
// 查询邻接矩阵第v行(第一个非0元素)且未被访问过
// 从该顶点出发
visited[v] = 1; // 辅助数组中该顶点的位置=1
printf("%c ", G.Vertex[v]); // 输出该顶点
for (int i = 0; i < G.cur_v; ++i)
{
if (G.Edge[v][i] != 0 && visited[i] != 1) // 邻接矩阵第v行第1个非0元素且未被访问过
DFS(G, i); // 从该顶点出发
}
}
int main()
{
int i, j;
Graph G;
Create(G);
printf("顶点: ");
for (i = 0; i < G.cur_v; ++i)
printf("%c ", G.Vertex[i]);
printf("\n边: \n");
for (i = 0; i < G.cur_v; ++i)
{
for (j = 0; j < G.cur_v; ++j)
printf("%d ", G.Edge[i][j]);
printf("\n");
}
printf("深度优先搜索: ");
DFS(G, 0);
printf("\n");
return 0;
}
2、BFS广度优先搜索
#include <cstdio>
#include <iostream>
#include <queue>
// 图的顺序存储
// 邻接矩阵
#define MAXSIZE 100
struct Graph
{
char Vertex[MAXSIZE]; // 顶点集
int Edge[MAXSIZE][MAXSIZE]; // 边集
int cur_v; // 现有顶点数目
int cur_e; // 现有边数目
};
// 建立图
void Create(Graph &G)
{
int i, j, num;
std::cout << "输入顶点的个数:\n";
scanf("%d", &num);
G.cur_v = num;
G.cur_e = 0;
std::cout << "输入顶点的值:\n";
for (i = 0; i < num; ++i)
std::cin >> G.Vertex[i];
printf("输入邻接矩阵:\n");
for (i = 0; i < num; ++i)
{
std::cout << "第" << i + 1 << "行: ";
for (j = 0; j < num; ++j)
{
std::cin >> G.Edge[i][j];
if (G.Edge[i][j] != 0)
++G.cur_e;
}
}
return;
}
// 广度优先搜索BFS
int visited[MAXSIZE] = {0};
void BFS(Graph G, int v)
{
// v顶点入队
// 访问队头元素 队头出队 原队头的邻接点(查询临接矩阵)入队
// 队列空 结束
int i, tmp;
std::queue<int> q;
q.push(v);
visited[v] = 1;
while (!q.empty())
{
tmp = q.front();
printf("%c ", G.Vertex[tmp]); // 访问队头元素
q.pop(); // 队头元素出队
for (i = 0; i < G.cur_e; ++i) // 查询邻接矩阵第tmp行
{
if (G.Edge[tmp][i] != 0 && visited[i] != 1) // 该顶点的(未被访问的/未在队列的)邻接点入队
{
q.push(i);
visited[i] = 1; // 辅助数组的该顶点的位置 = 1
}
}
}
}
int main()
{
int i, j;
Graph G;
Create(G);
printf("顶点: ");
for (i = 0; i < G.cur_v; ++i)
printf("%c ", G.Vertex[i]);
printf("\n边: \n");
for (i = 0; i < G.cur_v; ++i)
{
for (j = 0; j < G.cur_v; ++j)
printf("%d ", G.Edge[i][j]);
printf("\n");
}
printf("广度优先搜索: ");
BFS(G, 0);
printf("\n");
return 0;
}
3、最短路径 迪杰斯特拉算法 自定义实现
#include <cstdio>
#include <iostream>
#include <vector>
// 图的顺序存储
// 邻接矩阵
#define MAXSIZE 100
struct Graph
{
char Vertex[MAXSIZE]; // 顶点集
int Edge[MAXSIZE][MAXSIZE]; // 边集
int cur_v; // 现有顶点数目
int cur_e; // 现有边数目
};
// 建立图
void Create(Graph &G)
{
int i, j, num;
std::cout << "输入顶点的个数:\n";
scanf("%d", &num);
G.cur_v = num;
G.cur_e = 0;
std::cout << "输入顶点的值:\n";
for (i = 0; i < num; ++i)
std::cin >> G.Vertex[i];
printf("输入邻接矩阵:\n");
for (i = 0; i < num; ++i)
{
std::cout << "第" << i + 1 << "行: ";
for (j = 0; j < num; ++j)
{
std::cin >> G.Edge[i][j];
if (G.Edge[i][j] != 0)
++G.cur_e;
}
}
return;
}
int visited[MAXSIZE] = {0}; // 设置辅助数组--顶点加入S 判断V-S中没顶点
// 计算从某个顶点(源点)出发到其他各个顶点的最短路径(经过的所有边权值的和)
void Djstl(Graph G, int ShortestPath[], int n, int start)
{
// 输入从(源点)起点到其他顶点的最短直达路径长度表
// n个顶点进行n-1轮, 每一轮挑选1个顶点作为中转点更新最短路径长度表
int i, j, Min, Minloc;
std::vector<int>::iterator p, tmp; // 用来遍历VS, 选择顶点
// 1、初始化
std::vector<int> S;
S.push_back(start); // 源点加入集合S
std::vector<int> VS;
for (i = 0; i < n; ++i)
{
if (i != start)
VS.push_back(i); // 剩余顶点加入集合VS;
else
continue;
}
// 2、开始n-1轮挑选和更新最短路径长度表
for (i = 1; i < n; ++i)
{
// 3、每一轮从V-S集合中挑出1个顶点(距离源点最短(Shortest[]最小))加入S
Min = ShortestPath[*VS.begin()];
Minloc = *VS.begin();
tmp = VS.begin(); // 用来V_S中释放该顶点
for (p = VS.begin(); p != VS.end(); ++p)
{
if (ShortestPath[*p] < Min)
{
Min = ShortestPath[*p]; // 更新最小值
Minloc = *p; // 更新最小值的位置
tmp = p; // 找到该顶点了
}
}
S.push_back(*tmp); // 该顶点加入S
VS.erase(tmp); // VS删除该顶点
// 4、以该顶点为中转更新最短路径长度表
for (int j = 0; j < n; ++j)
{
if (G.Edge[start][Minloc] + G.Edge[Minloc][j] < ShortestPath[j])
ShortestPath[j] = G.Edge[start][Minloc] + G.Edge[Minloc][j];
}
}
return;
}
int main()
{
int i, j;
Graph G;
Create(G);
printf("验证创建图: \n");
printf("顶点: ");
for (i = 0; i < G.cur_v; ++i)
printf("%c ", G.Vertex[i]);
printf("\n边: \n");
for (i = 0; i < G.cur_v; ++i)
{
for (j = 0; j < G.cur_v; ++j)
printf("%d ", G.Edge[i][j]);
printf("\n");
}
printf("迪杰斯特拉算法:\n");
int Shortest[6] = {0, 1, 65535, 4, 4, 65535};
for (i = 0; i < 6; ++i)
printf("%d ", Shortest[i]);
printf("\n");
Djstl(G, Shortest, 6, 0);
printf("迪杰斯特拉算法:\n");
for (i = 0; i < 6; ++i)
printf("%d ", Shortest[i]);
printf("\n");
return 0;
}
3最短路径 迪杰斯特拉
#include <cstdio>
#include <iostream>
#include <algorithm>
#define INF 65535
// 图
#define MAXSIZE 1000
struct Graph
{
char Vertex[MAXSIZE];
int Edge[MAXSIZE][MAXSIZE];
int cur_v; // 现有顶点数
int cur_e; // 现有总边数
};
// 初始化图
void Create(Graph & G)
{
int i, j, n;
std::cout << "顶点的个数:\n";
std::cin >> n;
G.cur_v = n;
G.cur_e = 0;
std::cout << "顶点集:\n";
for (i = 0; i < n; ++i)
std::cin >> G.Vertex[i];
std::cout << "边的邻接矩阵:\n";
for (i = 0; i < n; ++i)
{
std::cout << "第" << i + 1 << "行: ";
for (j = 0; j < n; ++j)
{
std::cin >> G.Edge[i][j];
if (G.Edge[i][j] != INF)
++G.cur_e;
}
}
return ;
}
// 迪杰斯特拉算法一样--计算从起点到其余顶点的最短路径长度
// 假设从0号顶点出发--到其他顶点的最短路径长度表
int visited[MAXSIZE]; // 辅助数组
int distance[MAXSIZE]; // i顶点(起点)到其他顶点的最短路径长度表
void Dijkstra(Graph G)
{
std::cout << "初始化\n";
// 初始化
std::fill(distance, distance + MAXSIZE, INF); //从i顶点(源点)到其他顶点最短路径长度表
distance[0] = 0; // 假定从0号顶点出发
std::fill(visited, visited + MAXSIZE, 0); // 辅助数组
std::cout << "初始化结束\n";
// n个顶点n轮挑选--不设置集合S V-S
for (int i = 0; i < G.cur_v; ++i)
{
printf("第%d轮挑选\n", i + 1);
// 1、挑选顶点(距离源点最近)
int Minloc = -1, Min = INF;
for (int j = 0; j < G.cur_v; ++j)
{
if (visited[j] == 0 && distance[j] < Min)
{
Min = distance[j];
Minloc = j;
}
}
printf("挑中了%d顶点\n", Minloc);
if (Minloc == -1)
return ; // 没找到
// 2、以该顶点为中转点更新最短路径长度表
visited[Minloc] = 1; // 找到了距离源点距离最短的顶点
printf("第%d轮更新:\n", i + 1);
for (int k = 0; k < G.cur_v; ++k)
{
// 起点-中转点-中转点--没必要更新
// 起点-中转点-其他某个顶点 (中转点-其他顶点 没有边到达--没必要更新)
if (visited[k] == 0 && G.Edge[Minloc][k] != INF && distance[Minloc] + G.Edge[Minloc][k] < distance[k])
{
distance[k] = distance[Minloc] + G.Edge[Minloc][k];
}
}
printf("最短路径长度表: ");
for (int m = 0; m < G.cur_v; ++m)
printf("%d ", distance[m]);
printf("\n");
printf("第%d轮更新结束\n", i + 1);
}
return ;
}
// 输出图
void Show(Graph G)
{
int i, j;
std::cout << "顶点个数: " << G.cur_v << " 边数: " << G.cur_e << "\n";
std::cout << "顶点信息:\n";
for (i = 0; i < G.cur_v; ++i)
std::cout << G.Vertex[i] << " ";
std::cout << "\n边的信息:\n";
for (i = 0; i < G.cur_v; ++i)
{
for (j = 0; j < G.cur_v; ++j)
{
std::cout << G.Edge[i][j] << " ";
}
std::cout << std::endl;
}
return ;
}
int main()
{
Graph G;
Create(G);
Show(G);
Dijkstra(G);
return 0;
}
3、全源最短路径 弗洛伊德
#include <cstdio>
#include <iostream>
#include <vector>
// 图G = (V, E); 顶点集 边集
#define MAXSIZE 100
struct Graph
{
char Vertex[MAXSIZE]; // 顶点集
int Edge[MAXSIZE][MAXSIZE]; // 边集
int cur_v; // 现有顶点数
int cur_e; // 现有边的数
};
// 初始化图
void Create(Graph &G)
{
int i, j, num;
std::cout << "顶点的个数: ";
std::cin >> num;
G.cur_v = num;
G.cur_e = 0;
std::cout << "顶点的值: ";
for (i = 0; i < num; ++i)
std::cin >> G.Vertex[i];
std::cout << "边集:\n";
for (i = 0; i < num; ++i)
{
std::cout << "第" << i + 1 << "行: ";
for (j = 0; j < num; ++j)
{
std::cin >> G.Edge[i][j];
if (G.Edge[i][j] != 65535) // 65535代表i j顶点之间没有边
++G.cur_e;
}
}
return;
}
// 输出图
void Show(Graph G)
{
int i, j;
printf("顶点集:\n");
for (i = 0; i < G.cur_v; ++i)
printf("%c ", G.Vertex[i]);
printf("\n边集:\n");
for (i = 0; i < G.cur_v; ++i)
{
for (j = 0; j < G.cur_v; ++j)
printf("%d ", G.Edge[i][j]);
printf("\n");
}
return;
}
// 弗洛伊德算法--全源最短路径--求图中任意2顶点之间的最短路径长度(经过所有的边的权的和)
// 执行n轮迪杰斯特拉算法
int Shortest[6][6] =
{{0, 1, 65535, 4, 4, 65535}, {65535, 0, 65535, 2, 65535, 65535}, {65535, 65535, 0, 65535, 65535, 1}, {65535, 65535, 2, 0, 3, 65535}, {65535, 65535, 65535, 65535, 0, 3}, {65535, 65535, 65535, 65535, 65535, 0}};
// 最短路径长度Shortest[i][]; // 从i顶点到其他顶点的最短路径长度
void Floyd(Graph &G, int Shortest[][6], int n = 6)
{
// 任意2个顶点的最短路径长度
int i, j, k, Min, Minloc;
std::vector<int>::iterator p, tmp; // 用来遍历VS, 选择顶点
for (i = 0; i < n; ++i) // n轮更新最短路径长度表
{
// 输入从(源点)起点到其他顶点的最短直达路径长度表
// n个顶点进行n-1轮, 每一轮挑选1个顶点作为中转点更新最短路径长度表
// 1、初始化
std::vector<int> S;
S.push_back(i); // 源点加入集合S
std::vector<int> VS;
for (j = 0; j < n; ++j)
{
if (j != i)
VS.push_back(j); // 剩余顶点加入集合VS;
else
continue;
}
// 2、开始n-1轮挑选和更新最短路径长度表
for (j = 1; j < n; ++j)
{
// 3、每一轮从V-S集合中挑出1个顶点(距离源点最短(Shortest[]最小))加入S
Min = Shortest[i][*VS.begin()];
Minloc = *VS.begin();
tmp = VS.begin(); // 用来V_S中释放该顶点
for (p = VS.begin(); p != VS.end(); ++p)
{
if (Shortest[i][*p] < Min)
{
Min = Shortest[i][*p]; // 更新最小值
Minloc = *p; // 更新最小值的位置
tmp = p; // 找到该顶点了
}
}
S.push_back(*tmp); // 该顶点加入S
VS.erase(tmp); // VS删除该顶点
// 4、以该顶点为中转更新最短路径长度表
for (k = 0; k < n; ++k)
{
if (G.Edge[i][Minloc] + G.Edge[Minloc][k] < Shortest[i][k])
Shortest[i][k] = G.Edge[i][Minloc] + G.Edge[Minloc][k];
}
}
}
return;
}
int main()
{
int i, j;
Graph G;
Create(G);
Show(G);
for (i = 0; i < G.cur_v; ++i)
{
for (j = 0; j < G.cur_v; ++j)
printf("%d ", Shortest[i][j]);
printf("\n");
}
printf("弗洛伊德算法:\n");
Floyd(G, Shortest);
printf("全源最短路径长度:\n");
for (i = 0; i < G.cur_v; ++i)
{
for (j = 0; j < G.cur_v; ++j)
printf("%d ", Shortest[i][j]);
printf("\n");
}
return 0;
}
4、最小生成树 prim算法
#include <cstdio>
#include <iostream>
#include <algorithm>
#define INF 65535
// 图
#define MAXSIZE 1000
struct Graph
{
char Vertex[MAXSIZE];
int Edge[MAXSIZE][MAXSIZE];
int cur_v; // 现有顶点数
int cur_e; // 现有总边数
};
// 初始化图
void Create(Graph & G)
{
int i, j, n;
std::cout << "顶点的个数:\n";
std::cin >> n;
G.cur_v = n;
G.cur_e = 0;
std::cout << "顶点集:\n";
for (i = 0; i < n; ++i)
std::cin >> G.Vertex[i];
std::cout << "边的邻接矩阵:\n";
for (i = 0; i < n; ++i)
{
std::cout << "第" << i + 1 << "行: ";
for (j = 0; j < n; ++j)
{
std::cin >> G.Edge[i][j];
if (G.Edge[i][j] != INF)
++G.cur_e;
}
}
return ;
}
// 最小生成树---n顶点n-1条边的权和最小
// 普里姆算法和迪杰斯特拉算法类似
// 0、初始化S = {0}, V-S = {1, 2, 3, 4, 5}; //顶点代号
// 1、从V-S集合中挑选出1个顶点 (该顶点距离S集合距离最小), 该顶点加入S集合
// 2、该顶点到V-S的边加入边集distance[MAXSIZE] 更新边集(V-S中的剩余顶点到S集合的最短距离);
// 直到S = {0, 1, 2, 3, 4, 5, 6}; (S, distance)最小生成树
int visited[MAXSIZE]; // 辅助数组
int distance[MAXSIZE]; // 边集(选中的边)
int Prim(Graph G)
{
std::cout << "初始化\n";
// 初始化
std::fill(distance, distance + MAXSIZE, INF); //从i顶点(源点)到其他顶点最短路径长度表
distance[0] = 0; // 假定从0号顶点出发
std::fill(visited, visited + MAXSIZE, 0); // 辅助数组
int sum = 0; // 最小生成树的边权之和
std::cout << "初始化结束\n";
// n个顶点n轮挑选--不设置集合S V-S
for (int i = 0; i < G.cur_v; ++i)
{
printf("第%d轮挑选\n", i + 1);
// 1、挑选顶点(距离S集合最近)
int Minloc = -1, Min = INF;
for (int j = 0; j < G.cur_v; ++j)
{
if (visited[j] == 0 && distance[j] < Min)
{
Min = distance[j];
Minloc = j;
}
}
printf("挑中了%d顶点\n", Minloc);
if (Minloc == -1)
return -1; // 没找到
// 2、该顶点加入S 该顶点到S集合的边加入边集distance[]
visited[Minloc] = 1; // 找到了距离S集合距离最短的顶点
sum += distance[Minloc]; // 选中的该边加入
printf("第%d轮更新选中的边集:\n", i + 1);
for (int k = 0; k < G.cur_v; ++k)
{
// 选中的顶点-S集合--没必要更新
// 其他某个顶点-选中的顶点 (其他顶点-选中的顶点 没有边到达--没必要更新)
// 更新其他顶点(V-S集合中的)到S集合的最短距离
if (visited[k] == 0 && G.Edge[Minloc][k] != INF && G.Edge[Minloc][k] < distance[k])
{
distance[k] = G.Edge[Minloc][k];
}
}
printf("选中的边: ");
for (int m = 0; m < G.cur_v; ++m)
printf("%d ", distance[m]);
printf("\n");
printf("第%d轮更新选中的边集结束\n", i + 1);
}
return sum;
}
// 输出图
void Show(Graph G)
{
int i, j;
std::cout << "顶点个数: " << G.cur_v << " 边数: " << G.cur_e << "\n";
std::cout << "顶点信息:\n";
for (i = 0; i < G.cur_v; ++i)
std::cout << G.Vertex[i] << " ";
std::cout << "\n边的信息:\n";
for (i = 0; i < G.cur_v; ++i)
{
for (j = 0; j < G.cur_v; ++j)
{
std::cout << G.Edge[i][j] << " ";
}
std::cout << std::endl;
}
return ;
}
int main()
{
Graph G;
Create(G);
Show(G);
int all = Prim(G);
std::cout << "all = " << all << "\n";
return 0;
}
5、最小生成树 克鲁斯卡尔算法
#include <cstdio>
#include <iostream>
#include <algorithm>
#define INF 65535
// 图
#define MAXSIZE 1000
struct Graph
{
char Vertex[MAXSIZE];
int Edge[MAXSIZE][MAXSIZE];
int cur_v; // 现有顶点数
int cur_e; // 现有总边数
};
// 初始化图
void Create(Graph & G)
{
int i, j, n;
std::cout << "顶点的个数:\n";
std::cin >> n;
G.cur_v = n;
G.cur_e = 0;
std::cout << "顶点集:\n";
for (i = 0; i < n; ++i)
std::cin >> G.Vertex[i];
std::cout << "边的邻接矩阵:\n";
for (i = 0; i < n; ++i)
{
std::cout << "第" << i + 1 << "行: ";
for (j = 0; j < n; ++j)
{
std::cin >> G.Edge[i][j];
if (G.Edge[i][j] != INF)
++G.cur_e;
}
}
return ;
}
// 最小生成树---n顶点n-1条边的权和最小
// 克鲁斯卡尔算法--边贪心-
// 1、每一轮选择权最小的边
// 2、判断加入该边是否形成环---成环-弃掉该边 不成环-加入边集
// 直到选中了n-1条边-结束
int Kruskal(Graph G)
{
// 难? 判断加入该边后图是否成环?
// 该边的两个顶点在不同集合内S V-S--才不会成环
// 该边的两个顶点在同集合S 成环---引入并查集
}
// 输出图
void Show(Graph G)
{
int i, j;
std::cout << "顶点个数: " << G.cur_v << " 边数: " << G.cur_e << "\n";
std::cout << "顶点信息:\n";
for (i = 0; i < G.cur_v; ++i)
std::cout << G.Vertex[i] << " ";
std::cout << "\n边的信息:\n";
for (i = 0; i < G.cur_v; ++i)
{
for (j = 0; j < G.cur_v; ++j)
{
std::cout << G.Edge[i][j] << " ";
}
std::cout << std::endl;
}
return ;
}
int main()
{
Graph G;
Create(G);
Show(G);
return 0;
}