数据结构与算法09 之图
在计算机程序设计中,图是最常用的结构之一。图是一种与树有些相像的数据结构,实际上,从数学意义上说,树是图的一种。然而在计算机程序设计中,图的应用方式与树不同。
前面讨论的数据结构都有一个框架,这个框架都是由相应的算法设定的。比如说,二叉树是那样一个形状,就是因为那样的形状使它更容易搜索数据和插入新数据,树的边表示了从一个节点到另一个节点的快捷方式。而图通常有一个固定的形状,这是由物理或抽象的问题所决定的。比如说,图中节点表示城市,而边表示城市间的航班线,这些都是固定的。即,图的形状取决于真实世界的具体情况。在图中,我们称节点为顶点。
在大多数情况下,顶点表示某个真实世界的对象,这个对象必须用数据项来描述。例如顶点代表城市,那么它需要存储城市名字、海拔高度、地理位置等相关信息。因此通常用一个顶点类的对象来表示一个顶点。这里我们仅仅在顶点中存储了一个字母来标识顶点,同时还有一个标志位,用来判断该顶点有没有被访问过。
- class Vertex { //顶点类
- public char label; //label: eg.'A'
- public boolean wasVisited;
- public Vertex(char lab) {
- label = lab;
- wasVisited = false;
- }
- }
顶点对象能放在数组(这里用vertexList数组)中,然后用下标指示,也可以放在链表或其他数据结构中,但不论使用什么数据结构,存储只为了使用方便,这与边如何连接点没有关系。
前面提到的树的表示中,大多数情况下都是每个节点包含它的子节点的引用,也可以用数组表示树,数组中的节点位置决定了它和其他节点的关系,比如堆。然而,图并不像树那样拥有几种固定的结构,因为图的每个顶点可以与任意多个顶点连接。为了模拟这种自由形式的组织结构,需要用一种不同的方法表示边,一般用两种方式:邻接矩阵和邻接表。
邻接矩阵是一个二维数组,里面的数据表示两点间是否存在边。如果图有N个顶点,那么邻接矩阵就是N*N的数组,如下表所示:1表示有边,0表示没有边,也可以用true和false来表示。
A |
B |
C |
|
A |
0 |
1 |
1 |
B |
1 |
0 |
1 |
C |
1 |
1 |
0 |
邻接表是一个链表数组(或者链表的链表),每个单独的链表表示了有哪些顶点与当前顶点邻接,如下表所示:A邻接顶点有B、C和D。
顶点 |
包含邻接顶点的链表 |
A |
B->C->D |
B |
A->D |
C |
A |
D |
A->B |
下面讨论下图中的搜索。在图中实现的基本操作之一就是搜索从一个定到可以到达其他哪些顶点,或者找所有当前顶点可到达的顶点。有两种常用的方法可用来搜索图:深度优先搜索(DFS)和广度优先搜索(BFS),它们最终都会到达所有的连通顶点。深度优先搜索通过栈来实现,而广度优先搜索通过队列来实现。具体的见下面的程序:
- public class Graph {
- private final int MAX_VERTS = 20;
- private Vertex vertexArray[]; //存储顶点的数组
- private int adjMat[][]; //存储是否有边界的矩阵数组, 0表示没有边界,1表示有边界
- private int nVerts; //顶点个数
- private StackX stack; //深度搜索时用来临时存储的栈
- private QueueX queue; //广度搜索时用来临时存储的队列
- public Graph() {
- vertexArray = new Vertex[MAX_VERTS];
- adjMat = new int[MAX_VERTS][MAX_VERTS];
- nVerts = 0;
- for(int i = 0; i < MAX_VERTS; i++) {
- for(int j = 0; j < MAX_VERTS; j++) {
- adjMat[i][j] = 0;
- }
- }
- stack = new StackX();
- queue = new QueueX();
- }
- public void addVertex(char lab) {
- vertexArray[nVerts++] = new Vertex(lab);
- }
- public void addEdge(int start, int end) {
- adjMat[start][end] = 1;
- adjMat[start][end] = 1;
- }
- public void displayVertex(int v) {
- System.out.print(vertexArray[v].label);
- }
- /*
- * 深度优先搜索算法:做四件事
- * 1. 用peek()方法检查栈顶的顶点
- * 2. 试图找到这个顶点还未访问的邻节点
- * 3. 如果没有找到,出栈
- * 4. 如果找到这样的顶点,访问这个顶点,并把它放入栈
- * 深度优先算法类似于从树的跟逐个沿不同路径访问到不同的叶节点
- */
- public void depthFirstSearch() {
- //begin at vertex 0
- vertexArray[0].wasVisited = true; //make it
- displayVertex(0);
- stack.push(0);
- while(!stack.isEmpty()) {
- //get an unvisited vertex adjacent to stack top
- int v = getAdjUnvisitedVertex(stack.peek());
- if(v == -1) { //if no such vertex
- stack.pop();
- }
- else { //if it exists
- vertexArray[v].wasVisited = true;
- displayVertex(v);
- stack.push(v);
- }
- }
- //stack is empty, so we're done
- for(int i = 0; i < nVerts; i++) {
- vertexArray[i].wasVisited = false;
- }
- }
- //returns an unvisited vertex adj to v
- public int getAdjUnvisitedVertex(int v) {
- for(int i = 0; i < nVerts; i++) {
- if(adjMat[v][i] == 1 && vertexArray[i].wasVisited == false) {//v和i之间有边,且i没被访问过
- return i;
- }
- }
- return -1;
- }
- /*
- * 广度优先搜索算法:做四件事
- * 1. 用remove()方法检查栈顶的顶点
- * 2. 试图找到这个顶点还未访问的邻节点
- * 3. 如果没有找到,该顶点出列
- * 4. 如果找到这样的顶点,访问这个顶点,并把它放入队列中
- * 深度优先算法中,好像表现的要尽快远离起始点,在广度优先算法中,要尽可能靠近起始点。
- * 它首先访问其实顶点的所有邻节点,然后再访问较远的区域。这种搜索不能用栈,而要用队列来实现。
- * 广度优先算法类似于从树的跟逐层往下访问直到底层
- */
- public void breadthFirstSearch() {
- vertexArray[0].wasVisited = true;
- displayVertex(0);
- queue.insert(0);
- int v2;
- while(!queue.isEmpty()) {
- int v1 = queue.remove();
- //until it has no unvisited neighbors
- while((v2 = getAdjUnvisitedVertex(v1)) != -1) {
- vertexArray[v2].wasVisited = true;
- displayVertex(v2);
- queue.insert(v2);
- }
- }
- for(int i = 0; i < nVerts; i++) {
- vertexArray[i].wasVisited = false;
- }
- }
- }
其中StackX和QueueX类的代码如下:
- public class QueueX {
- private final int SIZE = 20;
- private int[] queArray;
- private int front;
- private int rear;
- public QueueX() {
- queArray = new int[SIZE];
- front = 0;
- rear = -1;
- }
- public void insert(int j) {
- if(rear == SIZE-1) {
- rear = -1;
- }
- queArray[++rear] = j;
- }
- public int remove() {
- int temp = queArray[front++];
- if(front == SIZE) {
- front = 0;
- }
- return temp;
- }
- public boolean isEmpty() {
- return (rear+1 == front || front+SIZE-1 == rear);
- }
- }
- public class StackX {
- private final int SIZE = 20;
- private int[] stack;
- private int top;
- public StackX() {
- stack = new int[SIZE];
- top = -1;
- }
- public void push(int j) {
- stack[++top] = j;
- }
- public int pop() {
- return stack[top--];
- }
- public int peek() {
- return stack[top];
- }
- public boolean isEmpty() {
- return (top == -1);
- }
- }
图中还有个最小生成树的概念,所谓最小生成树,就是用最少的边连接所有的顶点。对于给定的一组顶点,可能又很多种最小生成树,但是最小生成树边E的数量总是比顶点V的数量小1,即E=V-1。寻找最小生成树不需要关心边的长度,并不需要找到一条最短路径,而是要找最少数量的边(最小路径在带权图中讨论)。
创建最小生成树的算法与搜索算法几乎是相同的,它同样可以基于广度优先搜索和深度优先搜索,这里使用深度优先搜索。在执行深度优先搜索的过程中,如果记录走过的边,就可以创建一棵最小生成树,可能会感到有点奇怪。见下面的程序(是上面Graph类中的一个方法,加到Graph类中即可):
- public void minSpanningTree() {
- vertexArray[0].wasVisited = true;
- stack.push(0);
- while(!stack.isEmpty()) {
- int currentVertex = stack.peek();
- int v = getAdjUnvisitedVertex(currentVertex);
- if(v == -1) {
- stack.pop();
- }
- else {
- vertexArray[v].wasVisited = true;
- stack.push(v);
- displayVertex(currentVertex); //from currentV
- displayVertex(v); //to v
- System.out.print(" ");
- }
- }
- //stack is empty, so we're done
- for(int j = 0; j < nVerts; j++) {
- vertexArray[j].wasVisited = false;
- }
- }
图就探讨到这里,如有错误,欢迎留言指正~+
转载:http://blog.csdn.net/eson_15/article/details/51113376
数据结构与算法09 之图相关推荐
- 【数据结构与算法09】图
在计算机程序设计中,图是最常用的结构之一.图是一种与树有些相像的数据结构,实际上,从数学意义上说,树是图的一种.然而在计算机程序设计中,图的应用方式与树不同. 前面讨论的数据结构都有一个框架,这个框架 ...
- 数据结构与算法思维导图(学习笔记)
版本 数据结构与算法思维导图V1.0 V1.0分享版本这个可以直接看,不需要下载. 说明 1.free 2.目前内容主要包含内容包含: 数据结构与算法思维导图 包含:线性表.顺序结构.链式结构,栈与队 ...
- 数据结构与算法学习笔记——图 C++实现
数据结构与算法学习笔记--图 C++实现 1 概念 2 图的表示方法 3 算法 3.1 拓扑排序 3.2 图的搜索算法 3.2.1 广度优先搜索(BFS) 3.2.2 深度优先搜索(DFS) 3.3 ...
- 数据结构和算法 -- 学习导图
数据结构和算法 是作为程序员写出高效代码的基础,为了今后的两年在高效代码之路上持续精进,将按照此学习导图进行 算法和数据结构的刻意练习,同时也希望为同样有高效代码追求的伙伴们提供一条学习路径,共同进步 ...
- 数据结构与算法思维导图(目录)
(小甲鱼)数据结构与算法(全99讲完结版)学习刷完纪念. 下面是总结的学习内容思维导图.
- python中判断无向图是否有环_数据结构与算法:17 图
17 图 知识结构: 图1 知识结构 1. 图的基本概念与术语 1.1 图的定义 图由顶点集和边集组成,记为 . 顶点集:顶点的有穷非空集合,记为. 边集:顶点偶对的有穷集合,记为 . 边: 无向边: ...
- 数据结构与算法 各类数图概念集合
拓扑排序: 有向无环图才能进行拓扑排序: 理解:就是在大学期间所有的课程,你只有先学完计算机基础,才能学更加高深的课程,从一个入度为0的点出发,找下一个一直到最后就是拓扑排序: 前.中.后序排序: 前 ...
- 数据结构与算法 -- 树结构与图结构
树的概念 形式化定义:算法的集合树(Tree)是由一个或多个结点组成的有限集合T,其中有一个特定的称为根的结点:其余结点可分为(m≥0)个互不相交的有限集T1,T2,T3,-,Tm,每一个集合本身又是 ...
- 数据结构与算法:17 图
17 图 知识结构: 1. 图的基本概念与术语 1.1 图的定义 图由顶点集和边集组成,记为G=(V,E)G=(V,E)G=(V,E). 顶点集:顶点的有穷非空集合,记为V(G)V(G)V(G). 边 ...
最新文章
- 访问控制列表(ACL)基本的配置以及详细讲解
- php文件开放下载安全,php实现文件安全下载
- 关于 移动端 页面跳转的方赞
- iOS 进阶 - RUNTIME 运行时
- MRP区域“MRP Area”的定义以及作用
- 1365. How Many Numbers Are Smaller Than the Current Number 有多少小于当前数字的数字
- P1993 小 K 的农场
- “有趣”的投影:当PCA失效时怎么办?
- 编写一个Rubygem, 如何在gem 被Install之前运行一段程序?
- 基于JAVA+SpringMVC+Mybatis+MYSQL的校园帮管理系统
- 移动端布局:视口viewport的理解
- Xen Server 7.0 一直无法退出维护模式
- tomcat ---- 启动,关闭和配置等等
- paip.提升用户体验---业务SQL注入漏洞的分析与解决
- win10管理员权限怎么获得_终于解决了:你需要来自XXX的权限才能对此文件进行更改
- LaTex 打英文音标方法
- [面试题]1000瓶毒药里面只有1瓶是有毒的,问需要多少只老鼠才能试出那瓶有毒。
- 利用高德api定位当前位置
- 【Office】Visio无响应问题(打开形状样式功能区即卡死)的解决方案
- 影视剧里程序员使用的双显示屏,在生活中真的需要么?正经科普
热门文章
- MySQL 高可用架构 之 MHA (Centos 7.5 MySQL 5.7.18 MHA 0.58)
- IntelliJ - idea15.0.2 破解方法
- 一直出现 Enter passphrase for key '/root/.ssh/gitkey12.pub'
- POJ1328-Radar Installation
- [再寄小读者之数学篇](2014-06-22 求导数 [中国科学技术大学2014年高等数学B考研试题])...
- shmdt() 与 shmctl() 的区别
- 1.4建立网站的基本流程
- 开复学生网--没有学习的动力怎么办
- 交互原型细节提升之路
- 团购硝烟慢慢散去之时:从团购身上我们可以学到什么?