原理
图是一些顶点的集合,这些顶点通过边来连接。我们采用邻接表法来实现
结构体定义
定义图之前,要定义好边和顶点的结构体,具体内容代码中有注释
#define MAX 10
bool visted[MAX]; // 记录顶点有无被访问
// 边的定义
typedef struct _EdgeNode
{
int adjves; // 连接的顶点
int weight; // 边的权重
struct _EdgeNode* next; // 下一条边
}EdgeNode;
// 顶点的定义
typedef struct _VertexNode
{
string data; // 顶点数据
struct _EdgeNode* first; // 指向连接的第一条边
}VertexNode, AdjList;
// 图的定义
typedef struct _AdjListGraph
{
AdjList* adjlist;
int vex; // 顶点数
int edge; // 边数
}AdjListGraph;
代码实现
初始化
bool initAdj(AdjListGraph& adj)
{
adj.adjlist = new AdjList[MAX];
adj.vex = adj.edge = 0;
for (int i = 0; i < MAX; i++)
{
visted[i] = false;
}
return true;
}
创建图
我们通过控制台输入的方式来进行图的创建。
location函数是为了根据顶点的数据来找到图中对应的数组下标。
对于具体图的创建,采用的是前插法,可以看看代码。
// 根据数据找到图对应的数组下标
int location(AdjListGraph& adj, string c)
{
for (int i = 0; i < adj.vex; i++)
{
if (adj.adjlist[i].data == c)
{
return i;
}
}
return -1;
}
// 创建图
void greateAdj(AdjListGraph& adj)
{
cout << "输入图的边数和顶点数" << endl;
cin >> adj.edge >> adj.vex;
cout << "请输入所有顶点数据" << endl;
for (int i = 0; i < adj.vex; i++)
{
cin >> adj.adjlist[i].data;
adj.adjlist[i].first = NULL;
}
int i1, i2, weigth;
string a, b;
for (int i = 0; i < adj.edge; i++)
{
cout << "输入两个相邻的顶点和权重" << endl;
cin >> a >> b >> weigth;
i1 = location(adj, a);
i2 = location(adj, b);
if (i1 != -1 && i2 != -1)
{
EdgeNode* node = new EdgeNode;
node->adjves = i2;
node->weight = weigth;
node->next = adj.adjlist[i1].first;
adj.adjlist[i1].first = node;
}
else
{
cout << "不存在对应顶点的数组下标" << endl;
return;
}
}
}
深度遍历
visted数组是记录该顶点有无被访问。
深度遍历从一个点开始遍历,然后根据该点的边访问下一个顶点,一直下去,最后出现没有未访问的点返回上一个顶点,访问其他顶点。
void DFS(AdjListGraph& adj, int v)
{
int next;
if (visted[v]) return;
cout << adj.adjlist[v].data << " ";
visted[v] = true;
EdgeNode* tmp = adj.adjlist[v].first;
while (tmp)
{
next = tmp->adjves;
tmp = tmp->next;
if (visted[next] == false)
{
DFS(adj, next);
}
}
}
void DFS_Main(AdjListGraph& adj)
{
for (int i = 0; i < adj.vex; i++)
{
if (visted[i] == false)
{
DFS(adj, i);
}
}
}
广度遍历
广度遍历借助了队列,现访问一个顶点,然后访问相邻的顶点,然后对每个相邻的点,在访问他们相邻的点,知道访问结束。
void BFS(AdjListGraph& adj, int v)
{
queue<int> q;
q.push(v);
int cur;
int next;
while (!q.empty())
{
cur = q.front();
q.pop();
if (visted[cur] == false)
{
cout << adj.adjlist[cur].data << " ";
visted[cur] = true;
}
EdgeNode* tmp = adj.adjlist[cur].first;
while (tmp)
{
next = tmp->adjves;
tmp = tmp->next;
q.push(next);
}
}
}
void BFS_Main(AdjListGraph& adj)
{
for (int i = 0; i < adj.vex; i++)
{
if (visted[i] == false)
{
BFS(adj, i);
}
}
}
最短路径
采用的深度遍历,对于每一种可能都试一下,然后选出最短的路径。
int min_weigth = 0x7FFFFFFF; // 最大的int
int steps = 0; // 步数
int path[MAX] = { 0 }; // 走过的路径
int short_path[MAX] = { 0 }; // 最短的路径
void DFS(AdjListGraph& G, int start, int end, int weights)
{
if (start == end)
{
for (int i = 0; i < steps; i++)
{
cout << G.adjlist[path[i]].data << " ";
}
cout << "该路径的权重:" << weights << endl;
if (weights < min_weigth)
{
min_weigth = weights;
memcpy(short_path, path, sizeof(int) * steps);
}
}
visted[start] = true;
int cur = start;
EdgeNode* tmp = G.adjlist[cur].first;
while (tmp)
{
cur = tmp->adjves;
int weight = tmp->weight;
if (visted[cur] == false)
{
visted[cur] = true;
path[steps++] = cur;
DFS(G, cur, end, weight + weights);
visted[cur] = false;
path[--steps] = 0;
}
tmp = tmp->next;
}
}