关于算法的准确性,本人只测试了比较简单的情况,两个算法是否存在未发现的漏洞,本人不做任何担保
BFS算法:
类似于树的层序遍历,需要借助队列实现`
算法的基本流程:起始点——探索未遍历的邻接点——未遍历的邻接点作为新的起始点重复`
#include <iostream>
#include <vector>
#include <queue>
#include "adjacency_list.h"
using namespace std;
//构建邻接表
struct adjNode
{
int data;
adjNode *next;
};
struct Vertice
{
int vertice;
adjNode *next;
bool flag = false;
};
//函数声明
void BFS(vector<Vertice> &adjacenty_list,int n);
void adjSearch(vector<Vertice> &adjacenty_list, Vertice vertice, queue<int> &q);
void BFS(vector<Vertice> &adjacenty_list, int n)
{
queue<int> q;
adjacenty_list[n].flag = true;
q.push(adjacenty_list[n].vertice);
cout << adjacenty_list[n].vertice << endl; //测试以下是否按照我们想要的顺序进行了遍历
adjSearch(adjacenty_list, adjacenty_list[n], q);
q.pop();
BFS(adjacenty_list, q.front());
}
//该函数的作用是探索某一顶点所有未遍历的邻接点
void adjSearch(vector<Vertice> &adjacenty_list, Vertice vertice, queue<int> &q)
{
adjNode *tmp = vertice.next;
while (tmp) //邻接列表非空时,检测该链表是否已经遍历,如果没有遍历,则将其放入队列中,然后下一个邻接结点,反之,下一个,并continue
{
if (adjacenty_list[tmp->data].flag)
{
tmp = tmp->next;
continue;
}
q.push(tmp->data);
tmp = tmp->next;
}
}
//测试程序,大部分代码都是在读入一个想要的邻接表(图)
int main()
{
int n, x;
adjList adjLink;
vector<Vertice> adjacenty_list;
cout << "input the numbers of the vertices: " << endl;
cin >> n;
for (int i = 0; i < n; i++)
{
queue<adjNode> q;
Vertice vertice = {i, nullptr};
adjacenty_list.push_back(vertice);
cout << "input the adjcent point or #: " << endl;
while (cin >> x)
{
adjLink = (adjList)malloc(sizeof(adjNode));
if (!q.empty())
{
adjNode *tmp;
tmp = &q.front();
q.pop();
adjLink->data = x;
adjLink->next = nullptr;
q.push(*adjLink);
tmp->next = &q.front();
}
else
{
adjLink->data = x;
adjLink->next = nullptr;
adjacenty_list[i].next = adjLink;
q.push(*adjLink);
}
}
cin.clear();
cin.ignore();
}
BFS(adjacenty_list, 0);
}
图的DFS算法,类似于树的先序遍历,难点在于如何处理算法的记忆性
这就需要用到栈的数据结构来实现了,将遍历过的点记录在栈中,探索不下去了就返回,看看有没有值得继续探索的点
代码如下:
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include "adjacency_list.h"
using namespace std;
int k = 0;// k在这里是作为测试用例,用来观察DFS执行了几次,如果其次数等于V+E(顶点数与边数和),粗略表明,算法还不错
struct adjNode
{
int data;
adjList next;
};
struct V_list
{
int v;
adjList next;
bool flag = false;
};
stack<int> Stack;
vector<V_list> verticeList;
void DFS(V_list &vertice);
int adjSearch(V_list &adjNode);
int adjSearch(V_list &vertice) // 查询可以探索的邻接点
{
adjNode *tmp = vertice.next;
while (verticeList[tmp->data].flag) //对初学者而言,比较困难的点在这里。检测某顶点的邻接点是否都被遍历
{ //如果该点被遍历,那就下一个,如果没有被遍历,则对返回该点对应的顶点,作为下次DFS
tmp = tmp->next; //注意探索到最后的情形,tmp为空,需要跳出循环,并给出一个标志,表明该顶点没有未遍历的邻接点
if (tmp == nullptr) //该顶点为底部,需要回溯
break;
}
if (tmp != nullptr)
return (*tmp).data;
else
return -1;
}
void DFS(V_list &vertice)
{
k++;
cout << k << endl;
int next_v;
if (vertice.flag != true)
Stack.push(vertice.v);
vertice.flag = true;
next_v = adjSearch(vertice);
if (next_v != -1)
{
DFS(verticeList[next_v]);
}
else
{
Stack.pop();
if (Stack.empty())
return;
DFS(verticeList[Stack.top()]);
}
}
//测试程序与BFS相似但不相同,但部分代码在构建想要测试的图,或者说是邻接表
int main()
{
int n, x;
adjList adjLink;
cout << "input the numbers of the vertices: " << endl;
cin >> n;
for (int i = 0; i < n; i++)
{
queue<adjNode> q;
V_list vertice = {i, nullptr};
verticeList.push_back(vertice);
cout << "input the adjcent point or #: " << endl;
while (cin >> x)
{
adjLink = (adjList)malloc(sizeof(adjNode));
if (!q.empty())
{
adjNode *tmp;
tmp = &q.front();
q.pop();
adjLink->data = x;
adjLink->next = nullptr;
q.push(*adjLink);
tmp->next = &q.front();
}
else
{
adjLink->data = x;
adjLink->next = nullptr;
verticeList[i].next = adjLink;
q.push(*adjLink);
}
}
cin.clear();
cin.ignore();
}
DFS(verticeList[0]);
cout << k;
}