图的实现(带有深度/广度优先遍历/最小生成树算法)
来源:互联网 发布:郑州最专业seo公司 编辑:程序博客网 时间:2024/05/18 15:07
连通图
在图中,任意俩个节点都有一条路径,我们把这种图称为连通图。
生成树
连通图可能有多个边其中可能有环,但是生成树是由N个节点,N-1条边构成的连通图。它是一个特殊的连通图,其中没有环路。
最小生成树
因为N个节点,N-1条边构成生成树。那么就存在多个生成树,那么这么生成树中权值最小的生成树叫做最小生成树。
kruskal是构成最小生成树的一种算法,这个算法就是在图中不断地选出权值最小的边,一直选出N-1条即可。如果选的过程中遇见有构成环路的边,就选下一条权值次小的边即可。
广度优先/深度优先
这是俩种不同遍历图的方式,深度优先强调一直遍历,直到遍历到无法遍历的位置,再回退到上一节点,遍历与上一节点相邻的另一个节点。一般用递归实现。
广度优先,强调先把当前节点相邻的节点都访问了,然后在遍历相邻节点的相邻节点,一般用队列实现。因为队列是头删尾进,先进先出的原则,所以更好符合条件。
代码实现
#pragma once#include<string>#include<iostream>#include<vector>#include<unordered_map>#include<queue>#include"Union.h"using namespace std;struct Edge{ Edge( size_t src, size_t dst,int weight) :_weight(weight), _src(src), _dst(dst) {} int _weight; size_t _src; size_t _dst; Edge * next;};template<class V, bool digraph>class graph{public: graph() {} graph(vector<V>&vertrix) { _vertrix.reserve(vertrix.size()); int index = 0; for (auto&i : vertrix) { _vertrix.push_back(i); _hash[i] = index++; } linktable.resize(_vertrix.size()); } graph(const graph<V, digraph>&object) :_vertrix(object._vertrix), linktable(object.linktable), _hash(object._hash) {} graph<V, digraph>&operator=(const graph<V, digraph>object) { _vertrix.swap(object._vertrix); _hash.swap(object._hash); // this->linktable.swap(object.linktable); } void Addedge(const V&v1, const V&v2, int weight) { int src = _hash[v1]; int dst = _hash[v2]; _Addedge(src, dst, weight); if (digraph == false) _Addedge(dst, src, weight); } void BFS() { queue<int> qcon; qcon.push(0); vector<bool> visited(_vertrix.size(), false); Edge * pCur = NULL; int src = 0; while (!qcon.empty()) { src = qcon.front(); qcon.pop(); cout << _vertrix[src] << "->"; visited[src] = true; pCur = linktable[src]; while (pCur) { if (visited[pCur->_dst] == false) { qcon.push(pCur->_dst); visited[pCur->_dst] = true;//防止有的节点被多次push } pCur = pCur->next; } } } void DFS() { vector<bool> visited(_vertrix.size(), false); _DFS(0, visited); } bool kruskal(graph<V, digraph>&mintree) { mintree._vertrix = _vertrix; mintree._hash = mintree._hash; mintree.linktable.resize(linktable.size()); Uoion uoiobject(_vertrix.size()); struct compareGreater { bool operator()(Edge*parent, Edge*child) { return parent->_weight > child->_weight; } }; priority_queue<Edge*, vector<Edge*>, compareGreater> MinHeap; Edge * pCur = NULL; for (auto&i : linktable) { pCur = i; while (pCur) { if (pCur->_src < pCur->_dst) MinHeap.push(pCur); pCur = pCur->next; } } int N = _vertrix.size() - 1; if (MinHeap.size()<N) { cerr << "不是连通图,请先构造出来连通图" << endl; return false; } int src = 0; int dst = 0; while (N) { if (MinHeap.size() != 0) pCur = MinHeap.top(); else { cerr << "给的图无法构成最小生成树,可能环路过多,边数过少" << endl; return false; } MinHeap.pop(); src = pCur->_src; dst = pCur->_dst; if (uoiobject.GetRoot(src) != uoiobject.GetRoot(dst)) { mintree._Addedge(src, dst, pCur->_weight); uoiobject.uni(src, dst); --N; } } return true; } ~graph() { Edge * pCur = NULL; Edge * pNext = NULL; for (auto&i : linktable) { pCur = i; while (pCur) { pNext = pCur->next; delete pCur; pCur = pNext; } } }protected: void _DFS(size_t src, vector<bool>&visited) { cout << _vertrix[src] << "->"; visited[src] = true; Edge* pCur = linktable[src]; while (pCur) { if (visited[pCur->_dst] == false) _DFS(pCur->_dst, visited); pCur = pCur->next; } } void _Addedge(int src, int dst, int weight) { Edge * pCur = new Edge(src, dst, weight); pCur->next = linktable[src]; linktable[src] = pCur; } private: vector<V> _vertrix;//vector析构函数会类型萃取,如果所ADT类型一个一个调用 vector<Edge*> linktable;//析构函数,如果是内置类型什么都不做。 unordered_map<V, int> _hash;//所以linktable我们得自己释放 };#include<vector>using namespace std;class Uoion{public: Uoion(int n = 0) :_uoion(n + 1, -1) {} int GetRoot(int x) { while (_uoion[x] >= 0) { x = _uoion[x]; } return x; } int uni(int x, int y) { int Root = x; int Root2 = y; while (_uoion[Root] >= 0 || _uoion[Root2] >= 0) { if (_uoion[Root] >= 0) Root = _uoion[Root]; if (_uoion[Root2] >= 0) Root2 = _uoion[Root2]; } if (Root != Root2) { _uoion[Root] += _uoion[Root2]; _uoion[Root2] = Root; } return Root; } int Size() { int ret = 0; size_t size = _uoion.size(); for (size_t i = 0; i<size; ++i) { if (_uoion[i]<0) ++ret; } return ret; }private: vector<int> _uoion;};#include"graph.h"int main(){ vector<string> str = { "西安", "上海", "广州", "深圳", "北京" }; graph<std::string, false> graphobject(str); graphobject.Addedge("西安", "上海", 100); graphobject.Addedge("西安", "北京", 200); graphobject.Addedge("北京", "上海", 300); graphobject.Addedge("上海", "深圳", 400); graphobject.Addedge("深圳", "广州", 500); graphobject.Addedge("北京", "广州", 600); graphobject.DFS(); cout << endl; graphobject.BFS(); graph<std::string, false> mintree; graphobject.kruskal(mintree); mintree.DFS(); return 0;}
阅读全文
0 0
- 图的实现(带有深度/广度优先遍历/最小生成树算法)
- 图的邻接表(广度优先遍历,深度优先遍历,最小生成树(Kruskal算法))
- 邻接矩阵实现图+深度/广度优先遍历+最小生成树
- 邻接矩阵实现图+深度/广度优先遍历+最小生成树
- 图的建立(邻接矩阵)+深度优先遍历+广度优先遍历+Prim算法构造最小生成树(Java语言描述)
- 深度广度优先遍历最小生成树
- 图的邻接矩阵生成算法,深度优先遍历算法,广度优先遍历算法,Prime算法。):
- 图的深度优先(非递归)、广度优先、最小生成树的C++实现
- 图的深度优先搜索和广度优先搜索算法、最小生成树两种算法 --C++实现
- 图的广度遍历、深度遍历及最小生成树书算法(Prim、Kruskal)
- Java实现图的深度和广度优先遍历算法
- 图基本算法:深度广度遍历最小生成树
- 图的遍历之深度优先搜索算法&&广度优先优先算法的实现
- 图的深度优先遍历和广度优先遍历算法
- 树的广度优先遍历与深度优先遍历算法
- 树的广度(深度)优先遍历算法
- 图的深度优先遍历和广度优先遍历实现
- 深度优先算法、广度优先算法 与 图的遍历
- int与Integer的区别
- 希尔排序-c语言实现
- java泛型的通配符
- idea配置
- opencv_tutorial_code学习——opencv1语句
- 图的实现(带有深度/广度优先遍历/最小生成树算法)
- ListView点击后不响应
- 定时器详解
- Systemd 入门教程:命令篇
- iOS之Header Search Paths和User Header Search Paths和library searchpath
- XML文档 标签解读
- VUE之watch与computed
- codeforces 894D
- 《Android学习笔记》Android设计模式之单例模式