【基础算法】(10)图的概念及相关算法
来源:互联网 发布:剑网3自动更新网络断开 编辑:程序博客网 时间:2024/05/17 23:25
【基础算法】(10)图的概念及相关算法(第一篇)
Auther: Thomas Shen
E-mail: Thomas.shen3904@qq.com
Date: 2017/12/20
All Copyrights reserved !
- 基础算法10图的概念及相关算法第一篇
- 图的存储结构
- 1 邻接矩阵
- 2 邻接表
- 深度优先遍历DFS
- 1 基本概念
- 2 算法简述
- 11 递归实现
- 12 非递归实现
- 广度优先遍历BFS
- 1 基本概念
- 2 算法简述
- 代码实现
- References
- 图的存储结构
- 基础算法10图的概念及相关算法第一篇
1. 图的存储结构:
1.1 邻接矩阵:
使用二维数组来存储图的边的信息和权重,如下图所示的4个顶点的无向图:
从上面可以看出,无向图的边数组是一个对称矩阵。所谓对称矩阵就是n阶矩阵的元满足aij = aji。即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的。
如果换成有向图,则如图所示的五个顶点的有向图的邻接矩阵表示如下:
1.2 邻接表:
邻接矩阵是一种不错的图存储结构,但是对于边数相对较少的图,这种结构存在空间上的极大浪费,因此找到一种数组与链表相结合的存储方法称为邻接表。
邻接表的处理方法是这样的:
- 图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过,数组可以较容易的读取顶点的信息,更加方便。
- 图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以,用单链表存储,无向图称为顶点vi的边表,有向图则称为顶点vi作为弧尾的出边表
如下为无向图的邻接表表示:
从图中可以看出,顶点表的各个结点由data和firstedge两个域表示,data是数据域,存储顶点的信息,firstedge是指针域,指向边表的第一个结点,即此顶点的第一个邻接点。边表结点由adjvex和next两个域组成。adjvex是邻接点域,存储某顶点的邻接点在顶点表中的下标,next则存储指向边表中下一个结点的指针。
有向图的邻接表表示:
2. 深度优先遍历(DFS):
2.1 基本概念:
它从图中某个结点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到。若图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中的所有顶点都被访问到为止。
2.2 算法简述:
基本实现思想:
- 访问顶点v;
- 从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
- 重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。
2.1.1 递归实现:
1. 访问顶点v;visited[v]=1;//算法执行前visited[n]=02. w=顶点v的第一个邻接点;3. while(w存在) if(w未被访问) 从顶点w出发递归执行该算法; w=顶点v的下一个邻接点;
2.1.2 非递归实现:
1. 栈S初始化;visited[n]=0;2. 访问顶点v;visited[v]=1;顶点v入栈S3. while(栈S非空) x=栈S的顶元素(不出栈); if(存在并找到未被访问的x的邻接点w) 访问w;visited[w]=1; w进栈; else x出栈;
3. 广度优先遍历(BFS):
3.1 基本概念:
它是一个分层搜索的过程和二叉树的层次遍历十分相似,它也需要一个队列以保持遍历过的顶点顺序,以便按出队的顺序再去访问这些顶点的邻接顶点。
基本实现思想:
- 顶点v入队列。
- 当队列非空时则继续执行,否则算法结束。
- 出队列取得队头顶点v;访问顶点v并标记顶点v已被访问。
- 查找顶点v的第一个邻接顶点col。
- 若v的邻接顶点col未被访问过的,则col入队列。
- 继续查找顶点v的另一个新的邻接顶点col,转到步骤(5)。
直到顶点v的所有未被访问过的邻接点处理完。转到步骤(2)。
广度优先遍历图是以顶点v为起始点,由近至远,依次访问和v有路径相通而且路径长度为1,2,……的顶点。为了使“先被访问顶点的邻接点”先于“后被访问顶点的邻接点”被访问,需设置队列存储访问的顶点。
3.2 算法简述:
1. 初始化队列Q;visited[n]=0;2. 访问顶点v;visited[v]=1;顶点v入队列Q;3. while(队列Q非空) v=队列Q的对头元素出队; w=顶点v的第一个邻接点; while(w存在) 如果w未访问,则访问顶点w; visited[w]=1; 顶点w入队列Q; w=顶点v的下一个邻接点。
4. 代码实现:
采用邻接矩阵存储图的边信息:
/* * 定义图的结构 */ class Graph { static final int MaxNum=20; //最大节点数目 static final int MaxValue=65535; char[] Vertex = new char[MaxNum]; //定义数组,保存顶点信息 int GType; //图的类型0:无向图 1:有向图 int VertxNum; //顶点的数量 int EdgeNum; //边的数量 int[][] EdgeWeight = new int[MaxNum][MaxNum]; //定义矩阵保存顶点信息 int[] isTrav = new int[MaxNum]; //遍历标志 }
//创建邻接矩阵图 static void createGraph(Graph g){ int i , j , k; int weight; //权 char EstartV, EndV; //边的起始顶点 System.out.println("输入途中各顶点的信息"); for(i=0; i < g.VertxNum; i ++) { System.out.println("第" + (i+1) + "个顶点"); g.Vertex[i] = (scan.next().toCharArray() )[0]; } System.out.println("输入构成个遍的顶点和权值"); for(k=0;k<g.EdgeNum;k++) { System.out.println("第" + (k+1) + "条边:"); EstartV = scan.next().charAt(0); EndV = scan.next().charAt(0); weight = scan.nextInt(); for(i=0; EstartV!=g.Vertex[i] ; i++); //在已有顶点中查找开始节点 for(j=0; EndV != g.Vertex[j]; j++); //在已有节点上查找终结点 g.EdgeWeight[i][j] = weight; //对应位置保存权重,表示有一条边 if(g.GType == 0) //如果是无向图,在对角位置保存权重 g.EdgeWeight[j][i] = weight; } }
//清空图 static void clearGraph(Graph g){ int i,j; for(i=0; i< g.VertxNum; i++) for(j =0; j<g.VertxNum; j++) g.EdgeWeight[i][j] = Graph.MaxValue; //设置矩阵中各院素的值为MaxValue }
//输出邻接矩阵 static void OutGraph(Graph g){ int i,j; for(j = 0; j < g.VertxNum;j ++) System.out.print("\t" + g.Vertex[j]); //在第一行输入顶点信息 System.out.println(); for(i =0 ;i <g.VertxNum; i ++) { System.out.print( g.Vertex[i]); for(j = 0;j < g.VertxNum; j++) { if(g.EdgeWeight[i][j] == Graph.MaxValue) //若权值为最大值 System.out.print("\tZ"); //Z 表示无穷大 else System.out.print("\t" + g.EdgeWeight[i][j]); //输出边的权重 } System.out.println(); } }
//遍历图 static void DeepTraOne(Graph g,int n){//从第n个节点开始遍历 int i; g.isTrav[n] = 1; //标记为1表示该顶点已经被处理过 System.out.println("—>" + g.Vertex[n]); //输出节点数据 //添加处理节点的操作 for(i = 0; i< g.VertxNum; i++) { //if(g.EdgeWeight[n][i] != g.MaxValue && g.isTrav[n] == 0) if(g.EdgeWeight[n][i] != g.MaxValue && g.isTrav[i] == 0) { DeepTraOne(g, i); //递归进行遍历 } } }
//深度优先遍历 static void DeepTraGraph(Graph g){ int i; for(i = 0; i< g.VertxNum; i++) { g.isTrav[i]= 0; } System.out.println("深度优先遍历:"); for(i = 0; i< g.VertxNum ; i++) { if(g.isTrav[i] == 0) DeepTraOne(g,i); } System.out.println(); }
主函数:
public static void main(String[] args) { // TODO Auto-generated method stub Graph g = new Graph(); System.out.println("输出生成图的类型:"); g.GType = scan.nextInt(); //图的种类 System.out.println("输入图的顶点数量:"); g.VertxNum = scan.nextInt(); System.out.println("输入图的边数量:"); g.EdgeNum = scan.nextInt(); clearGraph(g); //清空图 createGraph(g); //生成邻接表结构的图 System.out.println("该图的邻接矩阵数据如下:"); OutGraph(g); //输出图 DeepTraGraph(g); //深度优先遍历图 }
References. :
- [ 1 ]. Coursera | Java程序设计 | PKU
- [ 2 ]. 图的概念和关于图的几个算法
- [ 3 ]. 《图论》——图的存储与遍历(Java)
- [ 4 ]. http://blog.csdn.net/hguisu/article/details/7712813
- [ 5 ]. http://www.cnblogs.com/dolphin0520/archive/2011/07/13/21052
36.html
- 【基础算法】(10)图的概念及相关算法
- 【基础算法】(11)树的概念及相关算法(一)
- 数据结构:图相关概念及遍历算法
- EM算法及相关概念
- 网络流概念及相关算法介绍
- 最大流相关概念及算法
- 网络流概念及相关算法介绍
- Apriori算法(基础及核心概念)
- EM算法(基础及核心概念)
- LR算法(基础及核心概念)
- 排序算法相关概念
- 算法相关概念
- (二)算法相关概念
- 树的相关基础算法
- 算法基础概念
- 算法基础概念
- SLAM相关概念及ORB算法步骤总结
- 数据结构与算法的基础概念
- 这篇文章挺有意思 关于如何自学web前端以及一些面试的经验分享
- jq验证
- CIFAR-10 训练与测试
- DMA buffer importing
- IO多路复用之poll总结
- 【基础算法】(10)图的概念及相关算法
- jquery记录停留时间
- C#中Datagridview的CheckBox获取选中状态的不同
- 遍历获取对象属性名和属性值
- Redis安装&&Jedis连接Redis
- SQL中的SqlConnection连接方式
- 使用枚举类,抽象类进行遍历实现类,匹配响应的牌型(十三水特殊牌型)
- Gradle基于Apache Ant和Apache Maven概念的项目自动化构建工具本地安装及eclipse 项目集成
- Electron:初体验