#include<iostream>
#include<map>
#include<queue>
#include<stack>
using namespace std;
//邻接矩阵
template<class T>
class MatrixG {
public:
~MatrixG() {
//delete数组是这样delete 然后如果输出c或者c[x] 目前不会输出东西 推断是 野指针指向地方为空
delete []c;
}
void init(int m, int n, int d) {
vSize = m;
T x, y;
c = new T[m];
for (int i = 0; i < m; ++i) {
cin >> c[i];
v[c[i]] = 0;
}
for (int i = 0; i < n; ++i) {
cin >> x >> y;
e[{x, y}] = 1;//pair+map建立二维矩阵可以这样用
if (d == 0)
e[{y, x}] = 1;//bfs和dfs对于有向图和无向图遍历次序可能不同
}
}
void bfs() {
clear();
queue<T>q; char ch;
for (int i = 0; i < vSize; ++i) {
if (!v[c[i]]) {
q.push(c[i]); v[c[i]] = 1;//放进去就要标记了而不是拿出来才标记,后者可能导致放进去多次
while (!q.empty()) {
ch = q.front(); q.pop();
cout << ch << " ";//相当于visit操作
for (int i = 0; i < vSize; ++i) {
if (e[{ch, c[i]}] && !v[c[i]])
q.push(c[i]), v[c[i]] = 1;
}
}
cout << endl;
}
}
}
void dfs() {
clear();
stack<T>st; char ch;
for (int i = 0; i < vSize; ++i) {
if (!v[c[i]]) {
st.push(c[i]); v[c[i]] = 1; cout << c[i] << " ";
while (!st.empty()) {
ch = st.top();
int i = 0;
for (; i < vSize; ++i) {
if (e[{ch, c[i]}]&&!v[c[i]]) {
st.push(c[i]); cout << c[i] << " ";
v[c[i]] = 1;
break;
}
}
if (i == vSize) {
st.pop();
}
}
cout << endl;
}
}
}
void clear() {
for (int i = 0; i < vSize; ++i)
v[c[i]] = 0;
}
private:
map<T, bool>v;
//如果使用unordered_map 则为散列函数,需要检查里面的哈希,所以当数据非常大的时候不建议使用。
//这种情况下如果使用会报错 我也不知道为什么
map<pair<T, T>, bool>e;
T* c;
int vSize;
};//模板类不可以直接建立对象
//邻接表
template<class T>
struct eNode {
T val;
eNode* next;
};
template<class T>//不管是类外定义函数还是N次定义结构体 只要涉及模板 都要加上这一句话
struct vNode {
int step;//用于记录哪个输入的T类型数据更早出现 无向图以从先出现的指向后出现的
bool visit;
eNode<T>* FirstEdge;
};
template<class T>
class ListG {
public:
~ListG() {
delete[]ch;
//也要记得释放链表!
for (int i = 0; i < vSize; ++i) {
eNode<T>* p = ma[ch[i]].FirstEdge, * q = ma[ch[i]].FirstEdge;
while (q) {
q = p->next;
delete p;
p = q;
}
}
}
void init(int m, int n, int d) {
vNode<T>vnode; T a, b, t; vSize = m;
ch = new T[m];//有new一定有delete啊呜呜呜 老是忘记!
//ch[i]存放着输入的T类型的数据 ma是以ch[i]为下标的存放结构体{visit,边集}的“数组”
for (int i = 0; i < m; ++i) {
cin >> ch[i];
vnode.FirstEdge = NULL;//注意任何链表的末尾都要指向NULL
vnode.visit = 0;
vnode.step = i;
ma[ch[i]] = vnode;
}
for (int i = 0; i < n; ++i) {
//建立的链表是从右到左连接再到根节点的
eNode<T>* p = new eNode<T>();
cin >> a >> b;
//根据我bfs和dfs的设置,有个外循环从出现顺序从早到晚遍历没有被标记的节点,所以无向图的方向一直是从早到晚的
//当他是无向图的时候,如果输入的边的两个节点的顺序是从晚到早的时候,将数据反过来
if (!d && ma[a].step > ma[b].step) {
t = a; a = b; b = t;
}
p->val = b;
p->next = ma[a].FirstEdge;
ma[a].FirstEdge = p;
}
}
void bfs() {
clear();//由于会同时测试bfs和dfs功能,所以每遍历一遍就要将bool数组置零
queue<vNode<T>>q; vNode<T>vnode;
for (int i = 0; i < vSize; ++i) {
if (!ma[ch[i]].visit) {
q.push(ma[ch[i]]);
ma[ch[i]].visit = 1;
cout << ch[i] << " ";//进入了就要标记为1 否则可能多次进入
while (!q.empty()) {
vnode = q.front(); q.pop();
while (vnode.FirstEdge) {
if (!ma[vnode.FirstEdge->val].visit) {
q.push(ma[vnode.FirstEdge->val]);
ma[vnode.FirstEdge->val].visit = 1;
cout << vnode.FirstEdge->val << " ";//这个输出相当于visit操作
}
vnode.FirstEdge = vnode.FirstEdge->next;//将边集遍历一遍
}
}
cout << endl;
}
}
}
void dfs() {
clear();
stack< vNode<T>>st;
vNode<T>vnode;
eNode<T>* p;
for (int i = 0; i < vSize; ++i) {
if (!ma[ch[i]].visit) {
st.push(ma[ch[i]]);
cout << ch[i] << " "; ma[ch[i]].visit = 1;
while (!st.empty()) {
vnode = st.top(); p = vnode.FirstEdge;
while (p) {
if (!ma[p->val].visit) {
st.push(ma[p->val]);
ma[p->val].visit = 1;
cout << p->val << " ";
break;//其实这个就相当于 只要找到第一个孩子 就从第一个孩子为双亲,然后出发
}
p = p->next;//和那个邻接矩阵差不多
}
if (!p)
st.pop();
}
cout << endl;
}
}
}
void clear() {
for (int i = 0; i < vSize; ++i) {
ma[ch[i]].visit = 0;
}
}
private:
map<T, vNode<T>>ma;
T* ch;
int vSize;
};
int main() {
int num;
int m, n, d;
MatrixG<char>mGraph;
ListG<char>lGraph;
while (1) {
cout << "---------请输入您需要的序号---------" << endl;
cout << "---------1.邻接矩阵初始化-----------" << endl;
cout << "---------2.邻接矩阵BFS--------------" << endl;
cout << "---------3.邻接矩阵DFS--------------" << endl;
cout << "---------4.邻接表初始化-------------" << endl;
cout << "---------5.邻接表BFS----------------" << endl;
cout << "---------6.邻接表DFS----------------" << endl;
cout << "---------7.退出----------------" << endl;
cin >> num;
switch (num)
{
case 1:
cin >> m >> n >> d;
mGraph.init(m, n, d);
break;
case 2:
mGraph.bfs();
break;
case 3:
mGraph.dfs();
break;
case 4:
cin >> m >> n >> d;
lGraph.init(m, n, d);
break;
case 5:
lGraph.bfs();
break;
case 6:
lGraph.dfs();
break;
case 7:
return 0;//return 0 才可以进入析构函数 exit(0)不可以 另外exit(1)是异常退出
break;
default:
cout << "您输入的序号有误,请重新输入: " << endl;
break;
}
}
}