常宝宝 北京大学计算机科学与技术系 chbb@pku.edu.cn 数据结构(六) 常宝宝 北京大学计算机科学与技术系 chbb@pku.edu.cn.

Slides:



Advertisements
Similar presentations
三级偏软考点. 第一章必考点 1. 计算机的进位数制 (1) 计算机中所有数据是二进制 0,1 表示 (2) 在现实生活中人们普遍使用十进制 如何把十进制转换成计算机所识别的二 进制?整数是除 2 取余法,小数是乘 2 取 整法.
Advertisements

第五章 二次型. 第五章 二次型 知识点1---二次型及其矩阵表示 二次型的基本概念 1. 线性变换与合同矩阵 2.
第七章 图 7.1 图的定义和术语 7.2 图的存储结构 7.3 图的遍历 7.4 图的连通性问题 7.5 有向无环图及其应用
复习:树 树的基本概念和术语 二叉树的概念及性质 二叉树的存储结构 遍历二叉树 线索二叉树 树的应用:哈夫曼树 顺序存储 链式存储 递归算法
最大团问题 回溯法应用 作者:余新华 时间:
第7章 图论基础与应用 PART A 《可视化计算》.
图 2008赛前知识点梳理三.
《数据结构》课程简介 李武军 南京大学计算机科学与技术系 2016年秋季.
数据结构 第7章 图.
第六章 图(一).
第七章 图 (Graph)
Ch.7 图 图是一种复杂的非线性结构 应用:AI、工程、数学、生物、计算机 结点间的逻辑关系:任两个结点都可能相关
第9章 图 图的基本概念 图的存储结构 图的实现 图的遍历 最小生成树 最短路径 拓扑排序 关键路径 主要知识点.
第七章 图 7.1 图的基本概念 7.2 图的存储表示 7.3 图的遍历 7.4 图的生成树 7.5 最短路径 7.6 拓扑排序
图(一).
第七章 图 1、图的基本概念 2、图的存储表示 3、图的遍历与连通性 4、最小代价生成树 5、最短路径问题 6、AOV网络和AOE网络.
图的遍历.
Chapter 6 Graphs.
第八章 图 图的基本概念 图的存储结构 图的遍历与连通性 最小生成树 最短路径 活动网络.
强连通分量 无向图 1、任意两顶点连通称该图为连通图 2、否则将其中的极大连通子图称为连通分量 A D C B E 有向图
第七章 图.
7.1 抽象数据类型图的定义 7.2 图的存储表示 7.3 图的遍历 7.4 最小生成树 7.5 重(双)连通图和关节点
第七章 图.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
第七章 图 知识点2:图的存储结构.
第七章 图 东南大学计算机学院 方效林 本课件借鉴了清华大学殷人昆老师 和哈尔滨工业大学张岩老师的课件.
第7章 图 本章主题:图的基本概念、图的存储结构和图的常用算法 教学目的: 教学重点:图的各种存储方式及其运算
数据结构 复习课 王彦 博士,副教授
第七章 图.
数据结构 Data Structure CSU 主讲人:王国军,郑瑾 中南大学信息院计科系
第6章 图 北京师范大学 教育技术学院 杨开城.
第4章 非线性规划 一维搜索方法 2011年11月.
数据结构 芦溪中学 胡小妹.
第7章 图 7.1 图的定义和术语 7.2 图的存储结构 7.3 图的遍历 7.4 图的连通性问题 7.5 有向无环图的应用
第11讲 树和二叉树(二).
第七章 图.
使用矩阵表示 最小生成树算法.
无向树和根树.
第6章 图 本章中介绍下列主要内容: 图的定义 图的存储结构 图的遍历操作 图的几个典型问题.
计算.
常宝宝 北京大学计算机科学与技术系 数据结构(三) 常宝宝 北京大学计算机科学与技术系
知识点回顾 拓扑排序 关键路径 应用领域、求解步骤、算法实现过程 应用领域 求解步骤
第八章 图 图的基本概念 图的存储表示 图的遍历与连通性 最小生成树 最短路径 活动网络.
Graphs.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
8.1 图的基本概念 8.2 图的存储结构 8.3 图的遍历 8.4 生成树 8.5 最短路径 8.6 拓扑排序 8.7 关键路径
数据结构学位考 复习课(3) 主要内容: 1. 图 2.查找、排序.
复习 图的定义和术语 图(Graph)、有向图、无向图、子图、有向完全图 、完全图、稀疏图、稠密图、权、网、邻接点、相关边、度、路径、路径长度、回路、简单路径、简单回路、连通、连通图、连通分量、强连通图、强连通分量、生成树 图的存储方法 给定一个图,画出邻接矩阵、邻接表 图的邻接矩阵和邻接表的存储算法.
顺序表的删除.
第四章 栈和队列 栈 ( Stack ) 队列 ( Queue ) 优先队列 (Priority Queue) 小结.
第8章 图 8.1 图的基本概念和基本操作 8.2 图的邻接矩阵存储结构 8.3 图的邻接表存储结构 8.4 图的其他存储结构
图(二).
知识点回顾 图的深度优先和广度优先遍历思想 图的深度优先遍历算法(用邻接表作为存储结构) 图的广度优先遍历算法(用邻接矩阵作为存储结构)
树和图 tree and graph 蔡亚星.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
第七、八次实验要求.
第六章 图 本章的主要内容是: 图的逻辑结构 图的存储结构及实现 图的连通性 最小生成树 最短路径 AOV网与拓扑排序 AOE网与关键路径.
#include <iostream.h>
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
动态规划 Floyd最短路径算法 高文宇
最小生成树.
第七章 图 £7.1 图的定义和术语 £7.2 图的存储结构 £7.3 图的遍历 £7.4 图的连通性问题 £7.5 有向无环图及其应用
4.2 图的存储结构(cont.) v1 v2 v3 v4 v5 vertex= v1 v2 v3 v4 v5 v
线性规划 Linear Programming
数据结构 第六章 图.
离散数学─归纳与递归 南京大学计算机科学与技术系
1、图的基本概念 2、图的存储结构 3、图的遍历与连通性
最小生成树 最优二叉树.
§2 自由代数 定义19.7:设X是集合,G是一个T-代数,为X到G的函数,若对每个T-代数A和X到A的函数,都存在唯一的G到A的同态映射,使得=,则称G(更严格的说是(G,))是生成集X上的自由T-代数。X中的元素称为生成元。 A变, 变 变, 也变 对给定的 和A,是唯一的.
3.3.2 两点间的距离 山东省临沂第一中学.
Presentation transcript:

常宝宝 北京大学计算机科学与技术系 chbb@pku.edu.cn 数据结构(六) 常宝宝 北京大学计算机科学与技术系 chbb@pku.edu.cn

内容提要 图状结构 -实现 -遍历 -拓扑排序 -最短路径

邻接矩阵 如果一个有向图含有n个顶点,则可以用n×n的布尔型矩阵adjacency[n][n]来存储图状结构。 若顶点v邻接到顶点w,则adjacency[v][w]= true,否则adjacency[v][w]= false 上述图状结构的表示方法称为邻接矩阵表示法。 对于无向图而言,采用邻接矩阵表示法,则邻接矩阵必为对称矩阵,即adjacency[v][w]= adjacency[w][v]。

邻接矩阵 邻接矩阵的C++实现 template <int max_size> class Graph { int count; //顶点数 bool adjacency[max_size][max_size]; //邻接矩阵 };

邻接表 除采用邻接矩阵表示图状结构外,还可以采用邻接表的方法实现图状结构。 在邻接表表示法中,n个顶点的图状结构可以表示成一个含有n个元素的线性表(称为顶点表)和n个线性表(称为邻接表)。每个顶点对应一个邻接表,顶点v对应的邻接表记录了顶点v邻接到的所有顶点。 顶点表和邻接表既可以采用链式线性表也可以采用顺序线性表。

邻接表

邻接表 邻接表的C++实现(顶点表为顺序表,邻接表为链表) typedef int Vertex; template <int max_size> class Graph { int count; //顶点数 List< Vertex> neighbors[max_size]; //邻接表 };

邻接表 邻接表的C++实现(顶点表、邻接表均为链表),这种实现也称为十字链表法。 class Edge; class Vertex { Edge* first_edge; Vertex* next_vertex; }; class Edge { Vertex* end_point; Edge* next_edge; }; class Graph { Vertex* first_vertex; };

图的遍历 和树的遍历类似,可以从图的某个顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这个过程称为图的遍历。 图的遍历比树的遍历复杂。 树的遍历始于根结点,图中没有根结点。 图中可能存在回路。 常用的图遍历方法 深度优先遍历 宽度优先遍历

深度优先遍历 深度优先遍历类似于树的先根遍历,其基本思想为: 从图中某个顶点v0出发,访问此顶点。然后依次从v0未被访问的邻接结点出发深度优先遍历图,直到图中所有和顶点v0连通的顶点都被访问到。 若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直到图中所有顶点都被访问到为止。

深度优先遍历 图中可能包含回路,因此在遍历过程中,一个顶点有可能被重复访问,为此设置一个布尔数组记录顶点是否被访问过。 bool visited[max_size]; 图有可能不连通,必须保证图中所有顶点被访问。

深度优先遍历算法 template <int max_size> void Graph<max_size>::depth_first( void (*visit)(Vertex&)) const { bool visited[max_size]; Vertex v; for (all v in G) visited[v]=false; for (all v in G) if ( !visited[v] ) traverse(v, visited, visit); } 不是程序,不能编译 template <int max_size> void Graph<max_size>::traverse( Vertex &v, bool visted[], void (*visit)(Vertex&)) const { Vertex w; visited[v] = true; (*visit)(v); for (all w adjacent to v) if ( !visited[w] ) traverse(w, visited, visit); }

宽度优先遍历 宽度优先遍历的基本思想为: 从图中某个顶点v0出发,访问此顶点。然后依次访问v0的各个未被访问过的邻接结点,然后分别从这些邻接结点出发宽度优先遍历图,直到图中所有和顶点v0连通的顶点都被访问到。 若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直到图中所有顶点都被访问到为止。

深度优先遍历算法 template <int max_size> void Graph<max_size>::breadth_first( void (*visit)(Vertex&)) const { Queue q; bool visited[max_size]; Vertex v, w, x; for (all v in G) visited[v]=false; for (all v in G) if ( !visited[v] ) { q.append(v); while( !q.empty() ) { q.retrieve(w); if ( !visited[w] ) { visited[w]=true; (*visit)(w); for ( all x adjacent to w ) q.append(x); } q.serve(); } } } 不是程序,不能编译

拓扑排序 拓扑排序不唯一! 什么是拓扑排序? 如果G=(V, E)是一个无环的有向图,则G上的拓扑排序指的是图中顶点满足下列条件的一种排序。 若 <v, w> ∈E,则在顶点v必须位于顶点w之前。 上图可能的拓扑排序 9 6 3 4 8 2 0 5 1 7 3 6 9 0 2 4 1 5 8 7 拓扑排序不唯一!

拓扑排序算法 常用拓扑排序方法: 深度优先排序 宽度优先排序 深度优先排序 (1)逆序产生拓扑排序,首先产生拓扑排序中最后一个顶点, 最后产生拓扑排序中的第一个顶点。 (2)找一个没有后继的顶点并将其作为拓扑排序的最后一个顶点。 (3)只有当一个顶点的所有后继顶点已经全部加入拓扑排序后,才可把该顶点加入到拓扑排序的最前端。

深度优先排序

拓扑排序的实现 有向图采用邻接表实现,顶点表采用顺序存储,邻接表采用链式存储。 typedef int Vertex; template <int graph_size> class Graph { int count; //顶点数 List< Vertex> neighbors[graph_size]; //邻接表 void recursive_depth_sort(Vertex v, bool visited[], List<Vertex>& topological_order); public: void depth_sort(List<Vertex>& topological_order); void breadth_sort(List<Vertex>& topological_order); };

深度优先排序的实现 template <int graph_size> void Graph<graph_size>::depth_sort(List<Vertex>& topological_order){ bool visited[graph_size]; Vertex v; for (v=0; v<count; v++) visited[v]=false; topological_order.clear(); for(v=0; v<count; v++) if (!visited[v]) recursive_depth_sort(v,visited, topological_order); }

深度优先排序的实现 template <int graph_size> void Graph<graph_size>:: recursive_depth_sort(Vertex v, bool *visited, List<Vertex>& topological_order) { visited[v]=true; int degree = neighbors[v].size(); for (int i=0; i<degree; i++) { Vertex w; neighbors[v].retrieve(i,w); if (!visited[w]) recursive_depth_sort(w,visited, topological_order); } topological_order.insert(0,v); }

宽度优先排序 宽度优先排序 (1)正向产生拓扑排序,首先产生拓扑排序中第一个顶点, 最后产生拓扑排序中最后一个顶点。 (2)找一个没有前趋的顶点并将其作为拓扑排序的第一个顶点。 (3)只有当一个顶点的所有前趋顶点已经全部加入拓扑排序后,才可把该顶点加入到拓扑排序的最后端。 用一个数组记录图中每个顶点的前趋的个数 int predecessor_count[graph_size];

宽度优先排序

宽度优先排序 template <int graph_size> void Graph<graph_size>::breadth_sort(List<Vertex>& topological_order){ topological_order.clear(); Vertex v, w; int predecessor_count[graph_size]; for (v=0; v<count; v++) predecessor_count[v]=0; for (v=0; v<count; v++) for (int i=0; i<neighbors[v].size(); i++) { neighbors[v].retrieve(i,w); predecessor_count[w]++; } Queue ready_to_process; for (v=0; v<count; v++) if (predecessor_count[v]==0) ready_to_process.append(v); while( !ready_to_process.empty()) { ready_to_process.retrieve(v); topological_order.insert(topological_order.size(), v); for (int j=0; j<neighbors[v].size(); j++) { neighbors[v].retrieve(j,w); predecessor_count[w]--; if (predecessor_count[w]==0) ready_to_process.append(w); } ready_to_process.serve(); } }

最短路径 最短路径通常是针对有向网络而言的。即边上带有权值的有向图。 假定G是一个有向网络,每条边上带有一个非负的权值,则从顶点v到顶点w的最短路径指的是从顶点v到顶点w的所有路径中权值之和最小的路径。顶点v称做源点,顶点w称做终点。

最短路径 顶点0和顶点1之间的最短路径是哪条路径? 怎样快速求出从某给定源点到其它顶点间的最短路径?

最短路径 Dijkstra算法 依最短路径的长度递增的次序求得各条路径。 设置一个集合S,该集合中存放从给定源点出发最短路径已知的所有顶点。 因此算法开始时,集合S中只有源点一个顶点。随着算法的进行,其余的顶点被逐步加入集合S。因此算法要解决的问题是确定每步应该加入哪个顶点? 设定一个数组 int distance[graph_size]; 记录从源点到其它顶点的距离。

最短路径 若顶点v已在S中,则distance[v]记录了从源点到顶点v的最短距离。 若顶点v还未加入S中,则distance[v]记录了从源点到某个S中的顶点w的最短距离加上边<w,v>的权值。 distance数组的初始化。 (1)若从源点邻接到顶点v(有边的情况),则distance[v]即为该边的权值。 (2)否则(无边的情况),则distance[v]为无穷大。 算法进行时,从distance中找一个最小值,并将其对应的顶点加入到S中。

最短路径 一旦某顶点v加入S,则重新计算尚未加入S的顶点所对应的数组distance元素值。更新规则为: 若distance[w] > distance[v]+weight(<v,w>),令 distance[w] = distance[v]+weight(<v,w>) 如此循环往复,直到把所有顶点加入S。

最短路径

Dijkstra算法的实现 有向网络用邻接矩阵实现。 template <class Weight, int graph_size> class Graph { int count; Weight adjacency[graph_size][graph_size]; public: void set_distances(Vertex source, Weight distance[]) const; };

Dijkstra算法的实现 template <class Weight, int graph_size> void Graph<Weight,graph_size>::set_distances(Vertex source, Weight distance[]) const { Vertex v,w; bool found[graph_size];//集合S for (v=0; v<count; v++) { found[v]=false; distance[v]=adjacency[source][v]; } found[source]=true;distance[source]=0; for (int i=0; i<count; i++ ) { Weight min=infinity;//numeric_limits<int>::max(); for (w=0; w<count; w++) if (!found[w]) if ( distance[w]<min) {v=w; min=distance[w];} found[v]=true; for (w=0; w<count; w++) if (!found[w]) if (min+adjacency[v][w] < distance[w]) distance[w]= min+adjacency[v][w]; } }

上机作业 在机器上用C++分别实现和图状结构有关的算法。 想一想为什么用Dijkstra算法可以求出最短路径?