【数据结构】:图
来源:互联网 发布:宽带网络套餐十机顶盒 编辑:程序博客网 时间:2024/06/14 10:45
图
- 1、定义是一种非线性结构,由顶点的集合和顶点间的关系的集合组成的一种数据结构。
Graph = (V,E);
V = {x|x是顶点的集合};
E = {<x,y> |(x,y属于V)}; - 2、图的分类有向图:顶点之间单向指引就是有向图无向图:顶点之间可以互相指引就是无向图
- 3、一些基本概念
1)完全图:在由n个顶点组成的无向图中,若有n(n-1)/2条边,则就是完全无向图
2)权重:在一些图中,边具有与之相关的数值,称为权重。
3)邻接顶点:如果(u,v)是图中的一条边,那么u,v互为邻接点。
4)度:与顶点相关联的边的数目
5)路径:一个顶点到另一个顶点所经过的痕迹
6)连通图:在无向图中,任意两个顶点之间都是连通的。
7)强连通图:在有向图中,若每一对顶点之间都存在路径,就称此图为强连通图。
8)生成树:若一个图有n个顶点,则有n-1条边的就是生成树
一个无向连通图的生成树是它的极小连通子图。
-4、图的存储方法
1)邻接矩阵
A:如何存储:
B:代码如何实现:
template<class V,class W>class GraphMatrix{public: //构造函数 GraphMatrix(V* v,size_t n,bool isDirected = false,const W& invalue = W()) :_v(v,v+n) ,_isDirected(isDirected) { _matrix = new W*[_v.size()]; for(size_t i = 0; i<n; i++) { _matrix[i] = new W[_v.size()]; for(size_t j = 0; j<n; j++) { _matrix[i][j] = invalue; } } } //给定一个顶点,如何得到这个顶点的下标 size_t GetIndex(const V& v) { for(size_t i = 0; i<_v.size(); i++) { if(_v[i] == v) { return i; } } assert(false); return 0; } //如何加一条边 void AddEge(const V& v1, const V& v2, const W& w) { size_t src = GetIndex(v1); size_t dest = GetIndex(v2); _matrix[src][dest] = w; if(_isDirected = false) //说明是无向图 { _matrix[dest][src] = w; } } //析构函数 ~GraphMatrix() { //先释放数据 for(size_t i = 0; i<_v.size(); i++) { delete[] _matrix[i]; } //后释放指针数组 delete[] _matrix; }private: vector<V> _v; //顶点的集合 W** _matrix; //边上权重的集合 bool _isDirected; //是否是与有向图};
2)邻接表
A:如何存储:
节点的设置:
template<class W>struct GraphLinkNode{ W _weight; //权重 GraphLinkNode<W*> _next; //下一个节点 size_t _src; size_t _dest; GraphLinkNode(size_t src,size_t dest,const W& weight = W()) :_weight(weight) ,_next(NULL) ,_src(src) ,_dest(dest) {}};
B:代码如何实现
template<class V, class W>class GraphLink{ typedef LinKEdge<W> Edge;public: GraphLink(V* vertexs, size_t n, const W& invalid = W(), bool isDirected = false) :_isDirected(isDirected) { _vertexs.resize(n); _vertexs.assign(vertexs, vertexs+n); _linkTables.resize(n, NULL); } size_t GetVertexIndex(const V& v) { for (size_t i = 0; i < _vertexs.size(); ++i) { if (_vertexs[i] == v) { return i; } } assert(false); return 0; } void _AddEdge(size_t src, size_t dst, const W& w) { // 头插 LinKEdge<W>* edge = new Edge(src, dst, w); edge->_next = _linkTables[src]; _linkTables[src] = edge; } void AddEdge(const V& v1, const V& v2, const W& w) { size_t src = GetVertexIndex(v1); size_t dst = GetVertexIndex(v2); _AddEdge(src, dst, w); if (_isDirected == false) { _AddEdge(dst, src, w); } }protected: vector<V> _vertexs; // 顶点集合 vector<Edge*> _linkTables; // 邻接表 bool _isDirected;};
邻接矩阵和邻接表的比较及各自的用途:
说明:
A:就定义来说:
邻接矩阵更适合直接定位
邻接表适合搜寻相邻节点
B:存储
邻接矩阵:在无向图的存储中,邻接矩阵的存储方式是一种对称矩阵,这样的存储方式可以节省很大的内存空间
邻接表:在无向图的存储中,是要将重复的元素再次进行存储的,因此会有空间上的开销
C:找寻元素的相邻边
邻接矩阵:要按行,列,依次进行查找,时间复杂度很高
邻接表:直接就遍历依次指向此节点的链表即可
- 5、图的遍历
1)分类:
深度优先遍历
广度优先遍历
2)代码如何实现
A:深度优先遍历
void DFS(const V& src) { size_t index = GetVertexIndex(src); vector<bool> visited(_vertexs.size(),false); visited[index] = true; cout<<_vertexs[index]<<"->"; _DFS(index,visited); } void _DFS(size_t src,vector<bool>& visited) { Edge* cur = _linkTables[src]; while(cur) { size_t dst = cur->_dst; if(visited[dst] == false) { cout<<_vertexs[dst]<<"->"<<" "; visited[dst] = true; _DFS(dst,visited); } cur = cur->_next; } }
B:广度优先遍历
void BFS(const V& src) { size_t index = GetVertexIndex(src); vector<bool> visited(_vertexs.size(),false); queue<int> q; q.push(index); while(!q.empty()) { size_t front = q.front(); if(visited[front] == false) { cout<<_vertexs[front]<<"->"; visited[front] = true; Edge* cur = _linkTables[front]; while(cur) { size_t dst = cur->_dst; if(visited[dst] == false) { q.push(dst); visited[dst] = true; cout<<_vertexs[dst]<<"->"; } cur = cur->_next; } } q.pop(); } }
0 0
- 数据结构---图
- 数据结构-图
- 数据结构:图
- 数据结构--图
- 数据结构----------------【图】 .
- 数据结构--图
- 【数据结构】图
- 数据结构--图
- 数据结构-图
- 数据结构 - 图
- 数据结构:图
- 数据结构-图
- 【数据结构】【图】
- 数据结构 图
- 数据结构 图
- 数据结构-图
- 数据结构 图
- 数据结构:图
- Java环境变量的配置(window下)
- Android 开源框架Glide应用(二)_占位&动画&Gif
- indexOf(String.indexOf 方法)
- kafka本地测试环境搭建
- Qt实现Label超链接效果
- 【数据结构】:图
- 对spring web启动时IOC源码研究
- 计算机是如何启动的?
- http://blog.csdn.net/crazy1235/article/details/43377545
- 业界难题-“跨库分页”的四种方案
- GLSurFaceView特性
- Java 判断字符是否是中文汉字
- Main函数中线程执行顺序
- 大数据量高并发访问的数据库优化方法