图的遍历(邻接矩阵+邻接表+无向图+有向图+bfs+dfs)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#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;
		}
	}
	
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值