数据结构与算法之十一 图

目标.

在本章中,你将学习到:

图相关的概念

实现图

应用图解决编程问题

考虑一种情况:

你必须访问一系列城市并且在结束的时候返回原来的城市。

对此,你需要:

找到最短或花费最少的路径,它开始于当前的城市,访问每一个预期的城市,然后返回原来的城市。

你如何解决此问题?

要解决此问题,你需要:

确定属于不同城市的信息的表示方式和城市间的距离的表示方式。

这种关系可以在图中表示。

图被定义为一种数据结构,它由一系列顶点(节点)和边(弧)组成。

它是数据项(顶点)的集合,这些数据项被相互连接以形成网络。

有两种类型的图:

有向图

无向图

为了实现图,你需要首先以图的形式表示给出的信息。

两种最通用的表示图的方式是:

邻接矩阵(二维数组)

邻接表   (链表)

遍历图表示访问图中的所有顶点。

你可以在下面两个方法的帮助下遍历图:

深度优先搜索 (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');

        }
    }
}

时间: 2024-10-25 15:12:15

数据结构与算法之十一 图的相关文章

数据结构和算法思维导图

需要重点以下10种数据结构和10种算法: 10 个数据结构:数组.链表.栈.队列.散列表.二叉树.堆.跳表.图.Trie 树 10 个算法:递归.排序.二分查找.搜索.哈希算法.贪心算法.分治算法.回溯算法.动态规划.字符串匹配算法 原文地址:https://www.cnblogs.com/gaopengpy/p/12276035.html

数据结构与算法 第四次实验报告 图

数据结构与算法 第四次实验报告 姓名:许恺 学号:2014011329 班级:计算机14-1     中国石油大学(北京)计算机科学与技术系 1.图的定义,文件为"Graph.h" #ifndef GRAPH_H//定义头文件 #define GRAPH_H #include<string>//引入标准库中的头文件 using namespace std; const int MaxSize=12; struct ArcNode//定义边表结点 { int adjvex;/

41 蛤蟆的数据结构笔记之四十一图的遍历之深度优先

41  蛤蟆的数据结构笔记之四十一图的遍历之深度优先 本篇名言:"对于我来说 , 生命的意义在于设身处地替人着想 , 忧他人之忧 , 乐他人之乐. -- 爱因斯坦" 上篇我们实现了图的邻接多重表表示图,以及深度遍历和广度遍历的代码,这次我们先来看下图的深度遍历. 欢迎转载,转载请标明出处: 1.  原理 图遍历又称图的遍历,属于数据结构中的内容.指的是从图中的任一顶点出发,对图中的所有顶点访问一次且只访问一次.图的遍历操作和树的遍历操作功能相似.图的遍历是图的一种基本操作,图的许多其它

【系列文章】数据结构与算法——图

---恢复内容开始--- 接触C语言是很早以前的事了,大概是在初中二年级.后来发现只学语言,不学算法根本没用,于是乎萌发了学习数据结构和算法的想法,但一直没有什么实际进展.直到今天,才决定好好研究一番(ps:今年大一,甚是惭愧),顺便把学习过程记录在这一系列文章之中.好了,废话不多说,开始我这一系列的文章.文中可能有错误,如果你发现了,我恳请你帮我指出.谢谢. 图——图能很方便的描述一些实际问题,常用于寻找最优解类型的问题.其他相关概念,百度百科说的很清楚了. 学习图大概有以下几个过程. 一.创

我的软考之路(五)——数据结构与算法(3)之图

图跟树一样,也是非线性结构,咋看起来有点复杂,其实它很简单.树具有层次关系,上层元素可以与下一个多个元素连接,但是只能和上层的一个元素连接.在图结构中,节点间的连接是任意的,任何一个元素都可以与其他元素连接. 图相对而言很简单,我们只介绍的图的遍历和最小生成树,现在我们开始. 遍历 1.概念 从图中某一个顶点出发,访问图中的每一个结点,并要求只能访问一次,不能重复访问. 2.方法 (1)广度优先遍历 基本思想:首先访问顶点,再访问顶点的全部未访问的邻结点,再访问邻结点的所有结点即可(类似树的层次

数据结构基础温故-5.图(中):最小生成树算法

图的“多对多”特性使得图在结构设计和算法实现上较为困难,这时就需要根据具体应用将图转换为不同的树来简化问题的求解. 一.生成树与最小生成树 1.1 生成树 对于一个无向图,含有连通图全部顶点的一个极小连通子图成为生成树(Spanning Tree).其本质就是从连通图任一顶点出发进行遍历操作所经过的边,再加上所有顶点构成的子图. 采用深度优先遍历获得的生成树称为深度优先生成树(DFS生成树),采用广度优先遍历获得的生成树称为广度优先生成树(BFS生成树).如下图所示,无向图的DFS生成树和BFS

数据结构与算法系列研究七——图、prim算法、dijkstra算法

图.prim算法.dijkstra算法 1. 图的定义 图(Graph)可以简单表示为G=<V, E>,其中V称为顶点(vertex)集合,E称为边(edge)集合.图论中的图(graph)表示的是顶点之间的邻接关系. (1) 无向图(undirect graph)      E中的每条边不带方向,称为无向图.(2) 有向图(direct graph)      E中的每条边具有方向,称为有向图.(3) 混合图       E中的一些边不带方向, 另一些边带有方向.(4) 图的阶      指

数据结构与算法——有向无环图的拓扑排序C++实现

拓扑排序简介: 拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从Vi到Vj的路径,那么在排序中Vi在Vj的前面. 如果图中含有回路,那么拓扑排序是不可能的.此外,拓扑排序不必是唯一的,任何合理的排序都可以. 对于上面的无环图:v1,v2,v5,v4,v3,v7,v6和v1,v2,v5,v4,v7,v3,v6都是合理的拓扑排序. 一个简单的求拓扑排序的思路: 1.先找出任意一个没有入边的顶点 2.然后显出该点,并将它和它邻接的所有的边全部删除. 3.然后,对图中其它部分做同样的处理.

数据结构与算法:概述+思维导图

还记得这个经典公式吗? 程序=数据结构+算法     可见数据结构和算法对于程序的重要性.基于此博主写了数据结构与算法系列随笔.下面先给出数据结构与算法的思维导图. 一.数据结构的基本概念 数据结构定义: 数据结构是一种存储和组织数据的方式,以便于访问和修改.数据结构包括数据的逻辑结构.数据的存储结构以及数据的运算,即按照某种逻辑关系组织起来的一批数据,按一定的映射方式把它存放在计算机的存储器中,并在这些数据上定义了一个运算的集合. 数据的逻辑结构:反映数据元素之间的关系.有集合.线性结构.树型