数据结构----图

        图的概念:图是一种非线性结构,由顶点即顶点的关系构成的一种数据结构;图的应用场景有:地图、用来描述社交关系、在网络中的路由选择。


     图的基本知识:


     图可以按照顶点间的边的方向分为:有向图 、 无向图;

     完全图 :在由n个结点构成的无向图中,若有(N(N-1))/2 条边,则成为完全图;

     权重:在一些图中,边具有与之相关的数值,称为权值;(权值可表示不同的意义,比如两顶点间的时间/距离等);

     度 :与某个结点相关联的边的数目,则称为这个顶点的度;

     连通图:在无向图中V1到V2有路径(V1,V2表示的是顶点),则成V1和V2是连通的;若一个图中任意两个顶点都是连通的,则称此图是连通图;

     强连通图:在有向图中,任意两个结点都是连通的,则称此图是强联通图;

     生成树:一个无向连通图的生成树是它的极小连通子图(若图中有N个结点,则生成树(不构成回路)由N-1条边构成);

     最小生成树:生成树中,N-1条边,权值和最小的生成树;

     

     图的存储:

     临接矩阵,临接表;

     图的遍历:

     深度优先遍历,广度优先遍历;

    分别用图的两种存储方式来实现图:

    

#pragma once  //临接矩阵存储图
#include<map>
#include<vector>
#include<string>
template<class V,class W,bool digraph = false>   //digraph 有向
class GraphMatrix
{
public:
	GraphMatrix(V* vertexs, size_t n) 
	{
		_vertexs.resize(n);
		for(size_t i = 0 ;i < n ;i++)
		{
			_vertexs[i] = vertexs[i];
			_indexMap[vertexs[i]] = i;
		}
		for(size_t i = 0 ; i < n;i++)
		{
               _matrix.resize(n);
			   for(size_t j = 0 ;j < n ;j++)
			   {
				   _matrix[i].resize(n,0);
			   }
		}
	}
	size_t GetVertexIndex(const V& v) 
	{
		return _indexMap[v];
	}
	void AddEdge(const V& src, const V& dst, const W& w) 
	{
		
		//if(_indexMap.count(src) == 0 )  ???当所插入的顶点不在临接矩阵时
		//{
  //          _vertexs.push_back(src);
		//    _indexMap[src] = _vertexs.size()-1;
		//	
		//}
		//if(_indexMap.count(dst) == 0 )
		//{
  //          _vertexs.push_back(dst);
		//	size_t i = _vertexs.size();
		//    _indexMap[dst] = _vertexs.size()-1;
		//}

        size_t srcIndex = GetVertexIndex(src);
        size_t dstIndex = GetVertexIndex(dst);
        _matrix[srcIndex][dstIndex] = w;
		if(digraph == false)
		{
           _matrix[dstIndex][srcIndex] = w;
		}

	}

protected: 
	map<V,size_t> _indexMap; 
	vector<V> _vertexs; // 顶点集合 
    vector<vector<W>> _matrix; // 临接矩阵
};
#pragma once
#include<queue>
template<class W>
struct LinkEdge//边
{
	W  _w ;
	size_t _srcIndex;
	size_t _dstIndex;
    LinkEdge<W>* _next;
	LinkEdge(size_t srcIndex,size_t dstIndex,const W& w)
		:_srcIndex(srcIndex)
		,_dstIndex(dstIndex)
		,_w(w)
		,_next(NULL)
	{
	}

};
template<class V,class W,bool digraph = false>
class GraphTable //临接表存储图
{
	typedef LinkEdge<W> Edge;
public: 
	GraphTable(V* vertexs, size_t n)
	{
		_vertexs.resize(n);             //拷贝顶点
                _linkTables.resize(n);
		for(size_t i = 0 ;i < n ;i++)
		{
			_vertexs[i] = vertexs[i];
			_indexMap[vertexs[i]] = i;
                        _linkTables[i] = NULL;
		}
    }
	size_t GetVertexIndex(const V& v)//获取顶点的下标
	{
		return _indexMap[v];
	}
	void _AddEdge(size_t srcIndex, size_t dstIndex, const W& w)  //链表头插
	{
        
                Edge* tmp = new Edge(srcIndex,dstIndex,w);
		tmp->_next = _linkTables[srcIndex];
                _linkTables[srcIndex] = tmp;
	}
	void AddEdge(const V& src, const V& dst, const W& w) 
	{
		size_t srcIndex = GetVertexIndex(src);
		size_t dstIndex = GetVertexIndex(dst);
                _AddEdge(srcIndex,dstIndex,w);
		if(digraph == false) //无向图
		{
			_AddEdge(dstIndex,srcIndex,w);
		}
	}
	void GFS(const V& src) //广度优先遍历
	{
		queue<size_t> q;
                size_t srcIndex = GetVertexIndex(src);
		vector<bool> visited ;
		visited.resize(_vertexs.size(),false);//访问标志
                q.push(srcIndex);
		while(!q.empty())
		{
			size_t  front = q.front();
			q.pop();
			if(visited[front] == false)
			{
				cout<<front<<_vertexs[front]<<"->";
			}
			else
				continue;
			Edge* cur = _linkTables[front];
			visited[front] = true;
			while(cur)
			{
                              if(visited[cur->_dstIndex] == false)
			      q.push(cur->_dstIndex);
			      cur = cur->_next;
			}
		}
		cout<<endl;
	}
	void DFS(const V& src)//深度优先遍历 
	{
           size_t srcIndex = _indexMap[src];
	   vector<bool> visited;
	   visited.resize(_vertexs.size(),false);
           _DFS(srcIndex,visited);
	   cout<<endl;
	}
	void _DFS(size_t srcIndex, vector<bool>& visited)
	{
		if(visited[srcIndex] == true)
			return;
		Edge* cur = _linkTables[srcIndex];
		cout<<srcIndex<<_vertexs[srcIndex]<<"->";
		visited[srcIndex] = true;
		while(cur)
		{
			if(visited[cur->_dstIndex] == false)
			{
                           _DFS(cur->_dstIndex,visited);
			}
			cur = cur->_next;
		}
	}
protected: 
	vector<V> _vertexs; 
	map<V,size_t> _indexMap; 
	vector<Edge*> _linkTables; //临接表存储的是边
};
有关图的算法:

最小生成树:

克鲁斯卡尔算法:用于求一个无向图的最小生成树;克鲁斯卡尔算法,每次从图中选取权值最小的边,在选取的时候还应注意N个顶点,则选取N-1条边;且所选的边之间不能构成回路(判断是否构成环可以用并查集来判断,若所选的两条边没有在同一个集合中,则它们不够成环);

普里姆算法(天然判环):

先随意选一个点加入归并点数组之中,然后选出与这个点关联的最小的权的点,输出,并把那个点也加入归并点数组之中,然后再从每一次都从归并点数组之中选一个点道不在这个数组之中的点的最小的权值,再把这个点也加入归并点数组,知道所有的点都在归并点数组之中

•1. 从某顶点 u0 出发,选择与它关联的具有最小权值的边(u0,v),将其顶点加入到生成树的顶点集合U中
•2. 每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u, v),把顶点v加入到U中
•3. 直到所有顶点都加入到生成树顶点集合U中为止

最短路径:

      迪杰斯特拉算法;



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值