第十二章 图

12.1 图的基本介绍

​ 图是一种数据结构,其中节点可以具有零个或多个相邻元素。两个节点之间的连接称为边。节点也可以称为顶点

为什么要有图

  1. 前面我们学习了线性表和树
  2. 线性表局限于一个直接前驱和一个直接后继的关系
  3. 树也只能有一个直接前驱也就是父节点
  4. 当我们需要表示多对多的关系时,就需要用到图

图的常用概念

  1. 顶点(vertex)
  2. 边(edge)
  3. 路径
  4. 无向图:顶点之间的连接没有方向
  5. 有向图:顶点之间的连接有方向
  6. 带权图:边带有权值,也叫做网

图的表示方式

​ 图的表示方式有两种:二维数组表示(邻接矩阵);链表表示(邻接表)

邻接矩阵

​ 邻接矩阵是表示图形中顶点之间相邻关系的矩阵

邻接表

  1. 邻接矩阵需要为每个顶点都分配 n 个边的空间,其实有很多边都是不存在的,会造成空间的一定损失
  2. 邻接表的实现只关心存在的边,不关心不存在的边。因此没有空间浪费,邻接表由数组+链表组成

12.2 图的创建

代码演示

package com.crisp.Graph;import java.util.ArrayList;
import java.util.Arrays;public class Graph {//存储顶点集合private ArrayList<String> vertexList;//存储图对应的邻接矩阵private int[][] edges;//表示边的数目private int numOfEdges;public static void main(String[] args) {int n = 5;// 节点个数String Vertexs[] = {"A", "B", "C", "D", "E"};//创建图Graph graph = new Graph(n);//循环添加顶点for (String vertex : Vertexs) {graph.insertVertex(vertex);}//添加边// A-B A-C B-C B-D B-Egraph.insertEdge(0, 1, 1);graph.insertEdge(0, 2, 1);graph.insertEdge(1, 2, 1);graph.insertEdge(1, 3, 1);graph.insertEdge(1, 4, 1);//显示graph.showGraph();}//构造器public Graph(int n) {//初始化矩阵和vertexListedges = new int[n][n];vertexList = new ArrayList<String>(n);numOfEdges = 0;}//插入节点public void insertVertex(String vertex) {vertexList.add(vertex);}//添加边public void insertEdge(int v1, int v2, int weight) {edges[v1][v2] = weight;edges[v2][v1] = weight;numOfEdges++;}//图中常用方法//返回节点个数public int getNumOfVertex() {return vertexList.size();}//得到边的数目public int getNumOfEdges() {return numOfEdges;}//返回节点i(下标)对应的数据 0->'A' 1->'B' 2->'C'public String getValueByIndex(int i) {return vertexList.get(i);}//返回v1和v2的权值public int getWeight(int v1, int v2) {return edges[v1][v2];}//显示图对应的矩阵public void showGraph() {for (int[] link : edges) {System.out.println(Arrays.toString(link));}}
}

12.3 图的遍历

图遍历的介绍

​ 所谓图的遍历,即是对结点的访问。一个图有那么多个结点,如何遍历这些结点,需要特定策略,一般有两种访问策略:

  1. 深度优先遍历
  2. 广度优先遍历

12.3.1 图的深度优先遍历

图的深度优先遍历(Depth First Search)

  1. 深度优先遍历,从初始访问结点出发,初始访问节点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点,可以这样理解:每次都在访问完当前结点后首先访问当前的第一个邻接结点
  2. 我们可以看到,这样的访问策略是优先纵向挖掘深入,而不是对一个结点的所有邻接结点进行横向访问
  3. 显然,深度优先搜索是一个递归的过程

深度优先遍历算法步骤

  1. 访问初始结点 v,并标记结点 v 为已访问
  2. 查找结点 v 的第一个邻接结点 w
  3. 若 w 存在,则继续访问 4,如果 w 不存在,则回到第 1 步,将从 v 的下一个结点继续
  4. 若 w 未被访问,对 w 进行深度优先遍历递归(即把 w 当作另一个 v ,然后进行步骤 123)
  5. 查找结点 v 的 w 邻接结点的下一个邻接结点,转到步骤 3

核心代码

//得到第一个邻接结点的下标 wpublic int getFirstNeighbor(int index){for(int j = 0; j < vertexList.size(); ++j){if(edges[index][j] > 0){return j;}}return -1;}//根据前一个邻接结点的下标来获取下一个邻接结点public int getNextNeighbor(int v1, int v2){for(int j = v2 + 1; j < vertexList.size(); ++j){if(edges[v1][j] > 0){return j;}}return -1;}//深度优先遍历算法// i 第一次就是 0private void DFS(boolean[] isVisited, int i){//首先我们访问该结点,输出System.out.print(getValueByIndex(i) + "->");//将该结点设置值为已经访问isVisited[i] = true;//查找结点 i 的第一个邻接结点int w = getFirstNeighbor(i);while(w != -1){//说明有if(!isVisited[w]){DFS(isVisited,w);}//如果 w 结点已经被访问过w = getNextNeighbor(i,w);}}//对 DFS 进行一个重载,遍历我们所有的结点,并进行 DFSpublic void DFS(){//遍历所有结点,进行DFS[回溯]for(int i = 0; i < getNumOfVertex(); ++i){if(!isVisited[i]){DFS(isVisited,i);}}}

12.3.2 图的广度优先遍历

图的广度优先遍历(Broad First Search)

​ 类似于一个分层搜索的过程,广度优先遍历需要使用一个队列以保持访问过的结点的顺序,以便按这个顺序来访问这些结点的邻接结点

广度优先遍历算法步骤

  1. 访问初始结点 v 并标记结点 v 为已访问
  2. 结点 v 入队列
  3. 当队列非空时,继续执行,否则算法结束
  4. 出队列,取得头结点 u
  5. 查找结点 u 的第一个邻接结点 w
  6. 若结点 u 的邻接结点 w 不存在,则转到步骤 3;否则循环执行以下三个步骤
    1. 若结点 w 尚未被访问,则访问结点 w 并标记为已访问
    2. 结点 w 入队列
    3. 查找结点 u 的继 w 邻接结点后的下一个邻接结点 w,转到步骤6

核心代码

//广度优先遍历private void BFS(boolean[] isVisited, int i){int u;// 表示队列的头结点对应的下标int w;// 邻接结点 w//队列,结点访问顺序LinkedList queue = new LinkedList();//访问结点,输出结点信息System.out.print(getValueByIndex(i) + "=>");//标记为已访问isVisited[i] = true;//将结点加入队列queue.addLast(i);while( !queue.isEmpty()){//取出队列的头结点下标u = (Integer)queue.removeFirst();//得到第一个邻接点的下标 ww = getFirstNeighbor(u);while(w != -1){//是否访问过if( !isVisited[w]){System.out.print(getValueByIndex(w) + "=>");//标记已经访问isVisited[w] = true;//入队queue.addLast(w);}//以 u 为前驱点,找 w 后面的下一个邻接点w = getNextNeighbor(u,w);//体现出广度优先}}}//遍历所有结点,都进行广度优先遍历public void BFS(){isVisited = new boolean[n];for(int i = 0; i < getNumOfVertex(); ++i){if( !isVisited[i]){BFS(isVisited,i);}}}

数据结构——图的创建以及遍历相关推荐

  1. 数据结构 - 二叉排序树BST(创建、遍历、删除节点)

    数组与链表区别: 二叉排序树的创建和遍历 代码实现 package tree.binarysorttree;public class BinarySortTreeDemo {public static ...

  2. 三十二、图的创建深度优先遍历(DFS)广度优先遍历(BFS)

    一.图的基本介绍 为什么要有图 前面我们学了线性表和树 线性表局限于一个直接前驱和一个直接后继的关系 树也只能有一个直接前驱也就是父节点 当我们需要表示多对多的关系时, 这里我们就用到了图. 图的举例 ...

  3. 图的创建以及遍历(邻接矩阵法存储图)

    #include<iostream> #define MVNUM 100 //最大顶点数 #define MAXQSIZE 100 //队列的最大长度 using namespace st ...

  4. Python写数据结构:二叉树的创建和遍历

    #!/usr/bin/python3.5 #_*_coding:utf-8_*_class Node:def __init__(self,value):self.data = valueself.lc ...

  5. 数据结构 --- 图的遍历 DFS、BFS

    什么是DFS.BFS? 一条线走到底,深度优先遍历,每一个顶点只遍历.只打印一次的方式:DFS.BFS 数据结构 --- 图的存储 单纯地把邻接顶点的邻接顶点打印出来,顶点重复遍历,打印多次 从 A→ ...

  6. 数据结构-图-知识点总结

    2019独角兽企业重金招聘Python工程师标准>>> 一.基本术语 图(graph):图是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图, ...

  7. 【恋上数据结构与算法 第二季】【04】图-基础实现_遍历_拓扑排序

    持续学习&持续更新中- 学习态度:脚踏实地 [恋上数据结构与算法 第二季][04]图-基础实现_遍历_拓扑排序 图的实现方案 邻接矩阵 邻接表 图的基础接口 顶点.边的定义 图的基础实现 图的 ...

  8. 数据结构之图的创建(邻接表)

    数据结构之图的基本概念中了解了图的基本概念,接下来对图的代码实现进行详解. 邻接无向图 1. 邻接表无向图介绍 邻接表无向图是指通过邻接表表示的无向图. 上面的图G1包含了"A,B,C,D, ...

  9. 数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树

    [本文谢绝转载,原文来自http://990487026.blog.51cto.com] 树 数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树二叉树的创建,关系建立二叉树的创建 ...

最新文章

  1. 如何用Python和深度神经网络识别图像?
  2. 李彦宏:正在发生的智能经济 4 大变革 | 赠书
  3. 《JAVA练习题目7》 定义一个素数生成器类PrimeGenerator,用于生成给定区间内的所有素数。(类PrimeGenerator都由类Main代替)
  4. spring学习之@ModelAttribute运用详解
  5. 安卓基础干货(四):安卓网络编程的学习
  6. CST,CET,UTC,GMT,DST,Unix时间戳几种常见时间概述与关系(转)
  7. 如何在远程桌面连接的服务器上访问本地磁盘
  8. C++ 句柄类的原理以及设计
  9. ubuntu 安装matlab+matconvnet
  10. RabbitMQ学习总结(一)
  11. 命名实体识别难在哪?
  12. 解决小程序插槽slot内容显示不对,无论是原生小程序还是uniapp开发的,解决办法如下
  13. 朴素贝叶斯--新浪新闻分类实例
  14. 微信小程序-组件的生命周期
  15. 跨考计算机英语自我介绍,跨专业考研英语自我介绍
  16. 序列化和json对比
  17. 【算法设计与分析】8枚硬币及n枚硬币问题
  18. c语言俄罗斯方块程序设计论文,c语言数据结构程序设计俄罗斯方块解读
  19. 8、多设备和异构插件
  20. 2P4M-ASEMI代理伟达原装单向可控硅2P4M

热门文章

  1. beaver彼_如何使用Beaver Builder创建自定义WordPress布局
  2. JS实现简单的登录注册页签
  3. 【参赛作品71】CentOS 7.9 安装 openGauss 2.1.0 之剥茧抽丝
  4. 基于ASAM ODS标准的试验数字化平台-WDP
  5. 桌面文件删除不掉的解决方案
  6. ClipCap: CLIP Prefix for Image Captioning
  7. 基于iPhone 上的运动协处理器M7判断用户当前的运动(姿态)类型
  8. thinkpad x250装黑苹果教程_Thinpad T系列安装MAC OS 黑苹果教程
  9. 百度地图点击获取定位信息以及定位的经纬度
  10. 无法为立即文档创建临时文件: 设备上没有空间(centos root 目录爆满)