图的基础和表示

1.图的基础

图是由节点和边组成的

图的主要应用:交通运输、社交网络、互联网、工作安排、脑区活动、程序状态执行

图的分类:有向图和无向图;有权图和无权图;连通图和非连通图

图的连通性:如果从图的任意一个结点可以到另外任意一个结点,说明这个图是连通的,下面这个图不是完全连通的

简单图:没有自环边和平行边的(一般题目处理的都是简单图,如果没有说明是简单图,需要处理一下)

自环边:有自己到自己的一条路径

平行边:代表两个节点之前有多条连接路径。比如交通运输:从A点到B点有多条路径

2.图的表示

图有两种表示方式:邻接矩阵、邻接表

          

    

邻接表适合表示稀疏图(边的个数远远小于这个图最大可以连接的数量)

邻接矩阵适合表示稠密图。

选择表达方式的时候主要考虑空间复杂度,

邻接矩阵的空间复杂度为O(V^2)

邻接表的空间复杂度为O(E)

一般都用邻接表。稠密的时候可以考虑用邻接矩阵。V是结点个数,E是边的条数

邻接矩阵的代码:

无权邻接矩阵和有权邻接矩阵的区别在于。无权邻接矩阵用0,1表示边

有权邻接矩阵,用权值w表示边(如果边的权值可以为0的话,那么就需要将边写成一个结构体,参考邻接表的写法)

#include <iostream>
#include <vector>
using namespace std;
//使用邻接矩阵来表示图 
class DenseGraph{
private:
	int n;//n代表结点数
	vector<vector<int> > Graph;//邻接矩阵 
	bool directed;//是否是有向图 
public:
	DenseGraph(int n,bool directed){
		this->n = n;
		this->directed = directed;
		for(int i=0; i<n; i++)
			Graph.push_back(vector<int>(n,0));
	} 
	//无权图:给图添加一条边
	void addEdge(int v,int m)
	{
		Graph[v][m] = 1;
		if(!directed) //无向图 
			Graph[m][v] = 1;
		
	} 
	//有权图:给图添加一条边
	void addEdge(int v,int m,int w)
	{
		Graph[v][m] = w;
		if(!directed) //无向图 
			Graph[m][v] = w;
	} 
	void print()
	{
		for(int i=0; i<n; i++)
		{
			for(int j=0; j<n; j++)
				cout<<Graph[i][j]<<" " ;
			cout<<endl;
		}
	}
	 
};
int main()
{
	//无权无向图 
	DenseGraph g1(7,false);
	g1.addEdge(0,1);
	g1.addEdge(0,2);
	g1.addEdge(0,5);
	g1.addEdge(0,6);
	g1.addEdge(5,3);
	g1.addEdge(3,4);
	g1.addEdge(5,4);
	g1.addEdge(4,6);
	g1.print();
	cout<<endl; 
	//有权有向图 
	DenseGraph g2(5,true);
	g2.addEdge(0,1,5);
	g2.addEdge(0,2,2);
	g2.addEdge(0,3,6);
	g2.addEdge(2,1,1);
	g2.addEdge(2,4,5);
	g2.addEdge(2,3,3);
	g2.addEdge(1,4,1);
	g2.addEdge(3,4,2);
	g2.print();
	
	return 0;
}

无权邻接表的代码:

#include <iostream>
#include <vector>
using namespace std;
//使用邻接表来表示无权图 
class SparseGraph{
private:
	int n;//n代表结点数
	vector<vector<int> > Graph;//邻接表
	bool directed;//是否是有向图 
public:
	SparseGraph(int n,bool directed){
		this->n = n;
		this->directed = directed;
		for(int i=0; i<n; i++)
			Graph.push_back(vector<int>());
	} 
	//给图添加一条边
	void addEdge(int v,int w)
	{
		Graph[v].push_back(w);
		if(!directed) //无向图 
			Graph[w].push_back(v);
	} 
	//判断两个点是否有边 O(n)
	bool hasEdge(int w, int v)
	{
		//查看是否存在w到v的边
		//即看 Graph[w]中是否存在一个值的v 
		for(int i=0; i<Graph[w].size(); i++)
		{
			if(Graph[w][i]==v)
				return true;
		}
		return false;
	}
	 
	void print()
	{
		for(int i=0; i<n; i++)
		{
			cout<<i<<":";
			for(int j=0; j<Graph[i].size(); j++)
				cout<<Graph[i][j]<<" " ;
			cout<<endl;
		}
	}
	 
};
int main()
{
	//无权有向图 
	SparseGraph g1(7,true);
	g1.addEdge(0,1);
	g1.addEdge(0,2);
	g1.addEdge(0,5);
	g1.addEdge(0,6);
	g1.addEdge(5,3);
	g1.addEdge(3,4);
	g1.addEdge(5,4);
	g1.addEdge(4,6);
	g1.print();
	cout<<g1.hasEdge(0,5)<<endl;
	cout<<g1.hasEdge(4,5)<<endl;
	return 0;
}

有权邻接表的代码:要使用一个结构体表示结点

#include <iostream>
#include <vector>
using namespace std;
//每个结点用一个结构体来表示
struct node{//新增结构体,表示与某个节点相连的节点号与权值
	int num;
	int weight;
}; 
//使用邻接表来表示有权图 
class SparseGraph{
private:
	int n;//n代表结点数
	vector<vector<node> > Graph;//邻接表
	bool directed;//是否是有向图 
public:
	SparseGraph(int n,bool directed){
		this->n = n;
		this->directed = directed;
		for(int i=0; i<n; i++)
			Graph.push_back(vector<node>());
	} 
	//给图添加一条边
	void addEdge(int v,int w,int weight)
	{
		node node;
		node.num=w;
		node.weight = weight;
		Graph[v].push_back(node);
		if(!directed) //无向图 
		{
			node.num=v;
			Graph[w].push_back(node);
		}
	} 
	//判断两个点是否有边 O(n)
	bool hasEdge(int w, int v)
	{
		//查看是否存在w到v的边
		//即看 Graph[w]中是否存在一个值的v 
		for(int i=0; i<Graph[w].size(); i++)
		{
			if(Graph[w][i].num==v)
				return true;
		}
		return false;
	}
	 
	void print()
	{
		for(int i=0; i<n; i++)
		{
			cout<<i<<":";
			for(int j=0; j<Graph[i].size(); j++)
				cout<<Graph[i][j].num<<"("<<Graph[i][j].weight<<")"<<" " ;
			cout<<endl;
		}
	}
	 
};
int main()
{
	//有权有向图 
	SparseGraph g2(5,true);
	g2.addEdge(0,1,5);
	g2.addEdge(0,2,2);
	g2.addEdge(0,3,6);
	g2.addEdge(2,1,1);
	g2.addEdge(2,4,5);
	g2.addEdge(2,3,3);
	g2.addEdge(1,4,1);
	g2.addEdge(3,4,2);
	g2.print();
	cout<<g2.hasEdge(0,3)<<endl;
	cout<<g2.hasEdge(4,5)<<endl;
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值