图(无向)的储存使用邻接矩阵(二维数组模拟)
约定:a[i][j]==1表示i+1点和j+1点有边连接,a[i][j]==0表示没有边连接,a[i][j]==-1表示的是i==j即同一个点
一、深度优先搜索法
“不撞南墙不回头式”的搜索,不从A点开始,先搜索一个与它有边的点,重复此操作,直到找不到点与当前点有边,则返回上一个点,寻找它是否还有其他与它有边且没有被访问过的点,有就继续前面的操作,否则继续放回至上一个点(非常相似与回溯法)。
#include<iostream>
using namespace std;
int num = 0;//记录被访问的点的个数
void dfs(int a[20][20],int book[50],int n,int cur)//a[20][20]数组用于储存图的信息(无向),book[i]==1表示的是点i已被访问,n表示的是图中顶点的个数,cur表示的当前正在被访问的点
{
num++;//访问的点个数自增
cout << cur << " ";//输出当前被访问的点
if (num == n)//访问完了所有点
return;
else
{
for (int i = 1; i <= n; i++)//对图中的每一个点进行匹配
{
if (a[cur][i] == 1 && book[i] == 0)//与当前访问的点有边,且没有被访问过
{
if (book[cur]==0)
book[cur] = 1;//将当前点置为已被访问了
dfs(a, book, n, i);//顺着这条线继续寻找与i有边且没有被访问过的点
}
}
return;
}
}
int main()
{
int a[20][20], book[50] = { 0 },n, m,t1,t2;//a[20][20]数组用于储存图(无向)的信息,book[i]==1表示的是点i已被访问,n表示的是图中顶点的个数,m表示的是图中的边数,t1,t2是输入边时的顶点参数
for (int i = 0; i < 20; i++)//初始化邻接矩阵
{
for (int j = 0; j < 20; j++)
{
if (i == j)//由于点和自身可达但没有边,所有特殊处理置为-1
a[i][j] = -1;
else//其余全部置零
a[i][j] = 0;
}
}
cout << "请输入图中顶点的个数:";
cin >> n;
cout << "请输入图中边的条数:";
cin >> m;
for (int i = 0; i < m; i++)//输入每条边的两个顶点的信息
{
cout << "请输入第 " << i + 1 << "条边的两个顶点:";
cin >> t1 >> t2;
while (t1 <= 0 || t1>n || t2 <= 0 || t2 > n)
{
cout << "输入的点不在图的范围内!请重新输入!" << endl;
cout << "请输入第 " << i + 1 << "条边的两个顶点:";
cin >> t1 >> t2;
}
a[t1][t2] = 1;//无向图,若点A有边到B,则B也有边到A
a[t2][t1] = 1;
}
dfs(a, book, n, 1);//从第一个点开始
cout << endl;
return 0;
}
二、广度优先搜索法
模拟队列,利用队列的线性和先入先出的特性
即从第一个点开始入队,然后将与它有边且没有被访问过的所有点都入队,然后模拟出队,再将与当前队头有边且没有被访问过的所有点都入队…直到队为空。
#include<iostream>
using namespace std;
int main()
{
int a[20][20], book[50] = { 0 }, n, m, t1, t2;//a[20][20]数组用于储存图(无向)的信息,book[i]==1表示的是点i已被访问,n表示的是图中顶点的个数,m表示的是图中的边数,t1,t2是输入边时的顶点参数
int point[30] = { 0 }, *head, *end;//point用于模拟队列,head头指针用于模拟出队,end尾指针用于模拟入队
head = point;//头指针指向数组的头部
end = head + 1;//尾指针用于指向存放下一个入队信息的空位置
for (int i = 0; i < 20; i++)//初始化邻接矩阵
{
for (int j = 0; j < 20; j++)
{
if (i == j)//由于点和自身可达但没有边,所有特殊处理置为-1
a[i][j] = -1;
else//其余全部置零
a[i][j] = 0;
}
}
cout << "请输入图中顶点的个数:";
cin >> n;
cout << "请输入图中边的条数:";
cin >> m;
for (int i = 0; i < m; i++)//输入每条边的两个顶点的信息
{
cout << "请输入第 " << i + 1 << "条边的两个顶点:";
cin >> t1 >> t2;
while (t1 <= 0 || t1>n || t2 <= 0 || t2 > n)
{
cout << "输入的点不在图的范围内!请重新输入!" << endl;
cout << "请输入第 " << i + 1 << "条边的两个顶点:";
cin >> t1 >> t2;
}
a[t1][t2] = 1;//无向图,若点A有边到B,则B也有边到A
a[t2][t1] = 1;
}
*head = 1;
book[*head] = 1;
while (head != end)//当两个指针不向碰,即模拟队列为空
{
cout << *head << " ";
for (int i = 1; i <= n; i++)
{
if (a[*head][i] == 1 && book[i] == 0)//每一个有边且没有被访问过的点都入队
{
book[i] = 1;
*end = i;//与head有边的入队
end++;//尾指针后移
}
}
head++;//头指针后移模拟出队
}
cout << endl;
return 0;
}
运行示例及结果:
刚刚入坑算法的萌新,如有错误还望各位路过的大佬多多指点。【抱拳】【抱拳】