基本数据结构:图

图的概念

图是由顶点与边构成的集合(V,E),V是所有顶点的集合,E是所有边的集和。

有向图

图中的边是具有方向性的,只能按箭头方向从一点到另一点。我们把以这个顶点为起点的有向边的数目称作该顶点的出度,把以这个顶点为终点的有向边的数目称作该顶点的入度。

无向图

图中的边无方向性,可以由任意方向从一点到另一点。我们把与该顶点相连的边的数目称作该顶点的度。

带权图

图中的边带有权值,可以理解为从一个顶点到与它相连顶点的距离。

图的存储

邻接矩阵

存储图的最简单的方式就是利用二维数组g[i][j],i表示边的起点,j表示边的终点,值表示该边的权值,当两条边不直接相连时权值设置为正无穷。

#include<iostream>
#include<cstring>
using namespace std;
const int N = 10000;
int g[N][N];
int main() {
    //以0x7f7f7f7f作为正无穷,memset是修改每个字节上的数据,int为4字节,每个字节修改为0x7f,合起来就是0x7f7f7f7f
	memset(g, 0x7f, sizeof(g));
	int n, m;//顶点数,边数; 
	cin >> n >> m;
	while (m--) {
		int u, v, w;//起始顶点,到达顶点,边权
		cin >> u >> v >> w;
        //无向图,两个方向都要赋值
		g[u][v] = w;
		g[v][u] = w;
        //如果是有向图,只用赋值连通的方向
	}
    //打印图
	for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j){
            if(g[i][j]!=0x7f7f7f7f)
                cout<<i<<"到"<<j<<"的距离为"<<g[i][j]<<endl;
        }
    }
	return 0;
}

邻接表

领接表保存所有的顶点,同时对每个顶点,保存其所有的边,每个顶点的所有边结点以链表形式组织起来,如果是带权图,边结点还要记录权值信息。

以上文图的概念中给出的无向图为例,其用邻接表表示如下:

实际代码编写中可以使用vector来简化编码过程:

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N = 150;
//邻接表 
struct Edge{
	int to,dis;
};
vector<Edge> head[N];
//添边 
void addEdge(int from,int to,int dis){
	Edge edge;
	edge.to=to;
	edge.dis=dis;
	head[from].push_back(edge);
}
int main(){
	int n,m;
	scanf("%d%d", &n, &m);
	int u,v,w;
	//邻接表建图 
	for(int i=1;i<=m;++i){
		scanf("%d%d%d",&u,&v,&w);
        //无向图,两个方向都要添边
		addEdge(u,v,w);
		addEdge(v,u,w);
        //如果是有向图,只用添连通方向的边
	}
    //打印图
	for(int i=1;i<=n;++i){
        for(int j=0;j<head[i].size();++j){
            Edge edge=head[i][j];
            printf("顶点%d到顶点%d的距离为%d",i,edge.to,edge.dis);
        }
    }
	return 0;
} 

十字链表

十字链表是为了解决有向图用邻接表存储时不便于计算顶点的入度,因此需要在邻接表的基础上额外保存入边。以上文图的概念中给出的有向图为例,其用十字链表表示如下:

邻接多重表

在邻接多重表表示下,无向图中每条边不需要两个方向都添加一次,因为每个边结点都保存了两个方向的信息。假设现要保存一条从顶点i到顶点j的边,则边结点要保存顶点i并指向下一条与i相连的边结点,同时要保存顶点j并指向下一条与j相连的边结点。以上文图的概念中给出的无向图为例,其用邻接多重表表示如下:

图的遍历

深度优先

深搜会优先沿某一分支一直搜到底,然后回溯到上一次出现分支的地方沿另一分支搜索,对于上面的图进行深度优先遍历,可能的一种结果为:ABCDEF GH I。

假设起点为A,从A出发,选择结点B所在分支,继续选择结点C所在分支,继续选择结点D所在分支,继续选择结点E所在分支,继续选择结点F所在分支,此时选择结点A所在分支发现重复,回退到结点F,选择结点G所在分支,此时选择结点B所在分支发现重复,回退到结点G,选择结点H所在分支,此时选择结点D所在分支发现重复,回退到结点H,继续选择结点E所在分支,仍然重复,回退到结点H,此时结点H已无分支可选,回退到结点G,同理结点G也无分支可选,回退到结点F,回退到结点E,回退到结点D,此时选择结点I所在分支,此后结点I无分支可选,一直回退到起点A都无新分支可选,深搜结束。

搜索结果为:ABCDEF GH I

广度优先

广搜会优先搜索该结点所有可能的分支(不会重复搜索已经遍历过的结点),对于上面的图进行广度优先遍历,可能的一种结果为:A BF CIGE DH。

若起点为A:

将起点A放入队列;        q:A

取出A,A能扩展出B、F,BF入队;        q:BF

        取出B,B能扩展出C、I、G,CIG入队;        q:FCIG

        取出F,F能扩展出E,E入队;         q:CIGE

                取出C,C能扩展出D,D入队;        q:IGED

                取出I,I能扩展出的结点此前已经被扩展过,无需重复入队;        q:GED

                取出G,G能扩展出H,H入队;        q:EDH

                取出E,E能扩展出的结点此前已经被扩展过,无需重复入队;        q:DH

                        取出D,D能扩展出的结点此前已经被扩展过,无需重复入队;        q:H

                        取出H,q为空,遍历完成;

遍历结果为:A BF CIGE DH。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值