数据结构与算法之十一 图
来源:互联网 发布:淘宝导航栏全屏 编辑:程序博客网 时间:2024/05/21 06:02
目标.
在本章中,你将学习到:
图相关的概念
实现图
应用图解决编程问题
考虑一种情况:
你必须访问一系列城市并且在结束的时候返回原来的城市。
对此,你需要:
找到最短或花费最少的路径,它开始于当前的城市,访问每一个预期的城市,然后返回原来的城市。
你如何解决此问题?
要解决此问题,你需要:
确定属于不同城市的信息的表示方式和城市间的距离的表示方式。
这种关系可以在图中表示。
图被定义为一种数据结构,它由一系列顶点(节点)和边(弧)组成。
它是数据项(顶点)的集合,这些数据项被相互连接以形成网络。
有两种类型的图:
有向图
无向图
为了实现图,你需要首先以图的形式表示给出的信息。
两种最通用的表示图的方式是:
邻接矩阵(二维数组)
邻接表 (链表)
遍历图表示访问图中的所有顶点。
你可以在下面两个方法的帮助下遍历图:
深度优先搜索 (DFS)
广度优先搜索(BFS)
算法: DFS(v)
1.将起始顶点v压入栈中。
2.重复直到栈变成空:
a.从栈中弹出顶点。
b.访问弹出的顶点。
c.将所有与弹出的顶点相邻接的未访问顶点压入栈。
d.
算法: BFS(v)
1.访问起始顶点v并且将它插入队列。
2.重复步骤3直到队列变成空。
3.从队列删除队头顶点,访问所有它未访问的邻接顶点,并且将它们插入到队列中。
4.
许多问题可以通过以图的形式减少它们而容易的解决。
图论是在不同领域中分析和解决问题的手段,例如计算机网络设计、城市计划、找到最短路径和分子生物学。
假设要在n 个城市之间建立通讯联络网,则连通n个城市只需要修建n-1条线路,如何在最节省经费的前提下建立这个通讯网?(比如说开封、安阳、许昌、驻马店、濮阳、焦作)
最小生成树:普里姆算法
取图中任意一个顶点 v 作为生成树的根,之后往生成树上添加新的顶点 w。在添加的顶点 w 和已经在生成树上的顶点v 之间必定存在一条边,并且该边的权值在所有连通顶点 v 和 w 之间的边中取值最小。之后继续往生成树上添加顶点,直至生成树上含有 n-1 个顶点为止。
克鲁斯卡尔算法
先构造一个只含 n 个顶点的子图 SG,然后从权值最小的边开始,若它的添加不使SG中产生回路,则在 SG上加上这条边,如此重复,直至加上 n-1条边为止。
解决最短路径问题
最短路径问题可以通过在图上应用Dijkstra算法来解决。
Dijkstra算法基于贪婪法。
Dijkstra算法的步骤如下:
1. 选择顶点v,对应与DISTANCE数组中记录的最小距离,以便v不是已经在FINAL中。
2. 添加v到FINAL。
3. 对于不在FINAL中的图中的每个顶点w重复:
a. 如果从v1到w的路径是比之前记录的从v1到w的距离要短:
i. 设置 DISTANCE[w]=DISTANCE[v] +边(v,w)的权重。
4. 如果FINAL没有包含任何顶点,跳转到步骤1。
小结
在本章中,你已经学到:
表示图的两种最常用的方法如下:
邻接矩阵
邻接表
遍历图表示访问图中的所有节点。
在图中,没有特定的顶点被指定为起始顶点。因此,图的遍历可能从任何顶点开始。
你可以在下面两种方法的帮助下遍历图:
DFS
BFS
图论是在不同领域中分析和解决问题的手段,例如计算机网络设计,城市计划,找到最短路径和分子生物学。
/* 问题描述:你必须以图的形式来表示一系列城市和他们之间的距离.编写一个程序来以邻接矩阵的形式表示图; */using System;using System.Collections.Generic;using System.Text;namespace GraphsUsingAdjMatrixInCSharp{ class Graph//图类 { private string[] vertices = new string[10];//定义一个字符串数组,用来存储各个顶点 private int[,] cost = new int[10, 10]; //定义一个邻接矩阵,来存储相应的边.(即顶点与顶点之间的距离.) private int n; //n为顶点的数量. public Graph()//构造函数 { n = 0;//初始化有0个顶点 for (int i = 0; i < 10; i++)//i:行 for (int j = 0; j < 10; j++)//j:列 { cost[i, j] = 0; } }//设置初始邻接矩阵的内容均为0 private bool edgeExists()//判断边是否存在 { for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) if (cost[i, j] != 0)//如果邻接矩阵存储的内容!=0,则返回真. return (true); return (false);//否则,即邻接矩阵的内容为0,返回假 } public void addVertex()//添加有n个城市方法. { string vname;//vname:顶点名称 Console.Write("请输入城市的个数(<10):"); n=Convert.ToInt32(Console.ReadLine()); for(int k=0;k<n;k++) { Console.Write("\n请输入城市: "); vname = Console.ReadLine(); int i = getIndex(vname);//获得顶点的索引 if (i != -1) { Console.WriteLine("\n城市已经存在."); return; } vertices[k] = vname; //将输入的城市名,作为图的顶点放入顶点数组. } } private int getIndex(String vname)//获得顶点索引方法 { for (int i = 0; i < n; i++) if (vertices[i] == vname) return (i);//如果顶点在数组中存在,则返回相应的索引. return (-1); /*如果顶点在数组中不存在,则返回-1;*/ } public void addEdge()//增加边方法;城市之间距离。 { string v1, v2;//v1,v2:始发城市、目标城市 int i1, i2; //i1,i2:获得始发城市、目标城市的索引 if (n == 0) { Console.WriteLine("\n没有城市存在,必须先创建城市."); return; } while (true) { Console.Write("\n请输入始发城市: "); v1 = Console.ReadLine(); i1 = getIndex(v1); if (i1 == -1)//存在,则退出循环. Console.WriteLine("\n出发城市不存在,请重试."); else break;//如果存在则退出循环;否则提示错误信息 } while (true)//同上,判断v2是否存在 { Console.Write("\n请输入目标城市: "); v2 = Console.ReadLine(); i2 = getIndex(v2); if (i2 == -1) Console.WriteLine("\n目标城市不存在,请重试."); else break; } Console.Write("\n请输入距离长度: "); cost[i1, i2] = Convert.ToInt32(Console.ReadLine());//设置i1,i2:位置为你从v1到v2的距离. } public void display()//显示图的顶点和边的情况. { if (n == 0) { Console.WriteLine("\n图不存在."); return; } Console.WriteLine("\n城市:"); for (int i = 0; i < n; i++) Console.WriteLine(vertices[i]); if (edgeExists())//边存在,则显示始发城市到目标城市的距离. { Console.WriteLine("\n距离:"); for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) if (cost[i, j] != 0) Console.WriteLine(vertices[i] + "->" + vertices[j] + " -- " + cost[i, j]); } } } class Graph_Program { static void Main(string[] args) { Graph g = new Graph(); char ch; do { Console.WriteLine(); Console.WriteLine("菜单"); Console.WriteLine("1. 添加城市"); Console.WriteLine("2. 添加距离"); Console.WriteLine("3. 显示");; Console.WriteLine("4. 退出"); Console.WriteLine(); Console.Write("请输入您的选择: "); ch = Convert.ToChar(Console.ReadLine()); switch (ch) { case '1': g.addVertex(); break; case '2': g.addEdge(); break; case '3': g.display(); break; case '4': break; default: Console.WriteLine("无效选择."); break; } } while (ch != '4'); } }}
/*扩充活动1,找出给定城市到所有城市之间的最短距离;迪杰斯特拉算法(Dijkstra)*/using System;using System.Collections.Generic;using System.Text;namespace GraphsUsingAdjMatrixInCSharp{ class Graph { private string[] vertices = new string[10];//定义一个字符串数组,用来存储各个顶点 private int[,] cost = new int[10, 10]; //定义一个邻接矩阵,来存储相应的边.(即顶点与顶点之间的距离.) private int n; //n为顶点的数量. int infinity = 9999999; //infinity:非常大的一个值, public Graph() { n = 0;//n:个顶点 for (int i = 0; i < 10; i++)//行 for (int j = 0; j < 10; j++)//列 { if (i == j) cost[i, j] = 0; else cost[i, j] = infinity; //infinity indicates that there is no edge from vertex i to vertex j } } private bool edgeExists()//判断边是否存在 { for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) if ((cost[i,j] != 0) && (cost[i,j] != infinity ))//如果邻接矩阵存储的内容!=0,则返回真. return (true); return (false);//否则,即邻接矩阵的内容为0,返回假 } public void addVertex()//添加有n个城市方法. { string vname;//vname:顶点名称 Console.Write("请输入城市的个数(小于10):"); n=Convert.ToInt32(Console.ReadLine()); for(int k=0;k<n;k++) { Console.Write("请输入城市: "); vname = Console.ReadLine(); int i = getIndex(vname);//获得顶点的索引 if (i != -1) { Console.WriteLine("\n城市已经存在."); return; } vertices[k] = vname; //将输入的城市名,作为图的顶点放入顶点数组. } } private int getIndex(String vname)//获得顶点索引方法 { for (int i = 0; i < n; i++) if (vertices[i] == vname) return (i);//如果顶点在数组中存在,则返回相应的索引. return (-1); /*如果顶点在数组中不存在,则返回-1;*/ } public void addEdge()//增加边方法. { string v1, v2; int i1, i2; if (n == 0) { Console.WriteLine("\n没有城市存在,必须先创建城市."); return; } while (true) { Console.Write("\n请输入始发城市: "); v1 = Console.ReadLine(); i1 = getIndex(v1); if (i1 == -1)//存在,则退出循环. Console.WriteLine("\n出发城市不存在,请重试."); else break; } while (true)//同上,判断v2是否存在 { Console.Write("\n请输入目标城市: "); v2 = Console.ReadLine(); i2 = getIndex(v2); if (i2 == -1) Console.WriteLine("\n目标城市不存在,请重试."); else break; } Console.Write("\n请输入距离长度: "); cost[i1, i2] = Convert.ToInt32(Console.ReadLine());//设置i1,i2:位置为你从v1到v2的距离. } public void display()//显示图的顶点和边的情况. { if (n == 0) { Console.WriteLine("\n图不存在."); return; } Console.WriteLine("\n城市:"); for (int i = 0; i < n; i++) Console.WriteLine(vertices[i]); if (edgeExists())//边存在,则显示始发城市到目标城市的距离. { Console.WriteLine("\n距离:"); for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) if ((cost[i, j] != 0) && (cost[i, j] != infinity)) Console.WriteLine(vertices[i] + "->" + vertices[j] + " - " + cost[i, j]); } } public void findShortestPath()//寻找最短路径. { int[] Distance = new int[10];//10个距离的数组 bool[] Final = new bool[10];//10个顶点. string source;//起始顶点. int src;//起始顶点标志 if (n == 0) { Console.WriteLine("\n图不存在,您必须先插入顶点和边"); return; } while (true) { Console.WriteLine("\n请键入起始顶点: "); source = Console.ReadLine(); src = getIndex(source); if (src == -1) Console.WriteLine("\n起始顶点不存在"); else break; } /*初始化距离数组*/ for (int i = 0; i < n; i++) Distance[i] = cost[src, i];//初始化:起始顶点到其他顶点的距离 Final[src] = true;//Final[0]=1 for (int i = 1; i < n; i++) //n-1循环 { /*查找最短距离.*/ int v = 0;/* Find a vertex that is not there in Final. Store its index in v */ for (int j = 0; j < n; j++) { if (Final[j] == false) { v = j; break; } } /*在顶点数组中找到距离顶点最小的顶点位置*/ for (int j = 0; j < n; j++) { if ((Final[j] == false) && (Distance[j] < Distance[v])) v = j; } Final[v] = true; /* Compute the distance of all nodes via node with index min */ for (int w = 0; w < n; w++) { if (Final[w] == false) //Final[1]==false { if (Distance[v] + cost[v, w] < Distance[w])//Distance[3]+cost[3,1]=3+~ <Distance[1]=5 结果不成立. Distance[w] = Distance[v] + cost[v, w]; } } } Console.WriteLine("\n顶点集合中的最小路径为" + source + "是: "); for (int j = 0; j < n; j++) { if (Distance[j] == infinity) Console.WriteLine(source + " -> " + vertices[j] + "=没有路径"); else Console.WriteLine(source + " -> " + vertices[j] + " = " + Distance[j]); } } } class Graph_Program { static void Main(string[] args) { Graph g = new Graph(); char ch; do { Console.WriteLine(); Console.WriteLine("菜单"); Console.WriteLine("1. 添加城市"); Console.WriteLine("2. 添加距离"); Console.WriteLine("3. 显示"); Console.WriteLine("4.从给定的顶点中寻找最短路径"); Console.WriteLine("4. 退出"); Console.WriteLine(); Console.Write("请输入您的选择: "); ch = Convert.ToChar(Console.ReadLine()); switch (ch) { case '1': g.addVertex(); break; case '2': g.addEdge(); break; case '3': g.display(); break; case '4': g.findShortestPath(); break; case '5': break; default: Console.WriteLine("无效选择."); break; } } while (ch != '5'); } }}
1 0
- 数据结构与算法之十一 图
- 【数据结构与算法】十一 最大公约数
- 数据结构与算法之高级排序(希尔/堆)<十一>
- 直通BAT--数据结构与算法十一(概率)
- (十一)数据结构之归并排序算法实现
- 数据结构与算法之----图
- 数据结构与算法之图
- 数据结构与算法之图计算
- Java数据结构与算法解析(十一)——红黑树
- Java数据结构与算法解析(十一)——红黑树
- Java数据结构与算法解析(十一)——红黑树
- Java数据结构与算法解析(十一)——红黑树
- 数据结构与C语言实现(十一)——图(下):最小生成树与Prim与Kruskal算法
- 数据结构实验之栈与队列十一:refresh的停车场
- 数据结构实验之栈与队列十一:refresh的停车场
- 数据结构实验之栈与队列十一:refresh的停车场
- 数据结构实验之栈与队列十一:refresh的停车场
- 数据结构实验之栈与队列十一:refresh的停车场
- memcached安装
- Longest Common Prefix - Javacript
- 文章标题
- ./configure,make,make install的作用
- 自定义滑动开关按钮-SwitchButton
- 数据结构与算法之十一 图
- 问答 | 35岁以后怎么混
- java中的反射,invoke方法
- 极客成长手记(附篇)——极客的快捷剑
- Add Binary - Javacript
- Implement strStr() - Javascript
- 相邻数字的基数不等比:skew 数
- 勾股定理一日一证连载23
- NKOJ 2150 广告印刷 单调队列