研究生考试.数据结构与算法之十一 图

简介: 研究生考试.数据结构与算法之十一 图

视频课堂https://edu.csdn.net/course/play/7621


目标.


在本章中,你将学习到:


图相关的概念


实现图


应用图解决编程问题




考虑一种情况:


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


对此,你需要:


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


你如何解决此问题?




要解决此问题,你需要:


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


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




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


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


有两种类型的图:


有向图


无向图



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


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


邻接矩阵(二维数组)


邻接表   (链表)




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


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


深度优先搜索 (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');
        }
    }
}
目录
相关文章
|
8月前
|
存储 算法
第七章 图【数据结构与算法】3
第七章 图【数据结构与算法】3
46 0
|
8月前
|
算法 vr&ar
第七章 图【数据结构与算法】2
第七章 图【数据结构与算法】2
36 0
|
4月前
|
存储 人工智能 算法
第七章 图【数据结构与算法】【精致版】
第七章 图【数据结构与算法】【精致版】
46 0
|
8月前
|
算法 Java
图【数据结构与算法java】
图【数据结构与算法java】
39 0
|
8月前
|
存储 人工智能 算法
第七章 图【数据结构与算法】1
第七章 图【数据结构与算法】1
63 0
|
10月前
|
存储 搜索推荐 算法
转:要考试了,排序算法总结看这里
常见的排序算法有:冒泡排序、选择排序、插入排序、归并排序、快速排序、堆排序、希尔排序、计数排序、桶排序和基数排序。
53 1
|
10月前
|
算法
【考试必考点——哈夫曼树】(贪心算法实现)
一、什么是哈夫曼树 当用 n 个结点(都做叶子结点且都有各自的权值)试图构建一棵树时,如果构建的这棵树的带权路径长度最小,称这棵树为“最优二叉树”,有时也叫“赫夫曼树”或者“哈夫曼树”。 二、哈夫曼树相关概念 1.路径 在一棵树中,一个结点到另一个结点之间的通路,称为路径。
|
11月前
|
存储 算法
【数据结构与算法】图的概述(内含源码)
【数据结构与算法】图的概述(内含源码)
75 0
|
存储 算法
数据结构/数据结构与算法实验三 图的相关算法实现
数据结构/数据结构与算法实验三 图的相关算法实现
96 0
数据结构/数据结构与算法实验三 图的相关算法实现
|
移动开发 算法 C++
数据结构与算法之图的应用
一.树之习题选讲-Tree Traversals Again 树习题-TTA.1 题意理解 非递归中序遍历的过程 ● 1. Push的顺序为先序遍历(pre) ● 2. Pop的顺序给出中序遍历(in) ● 树习题-TTA.2 核心算法 上图分别是先序、中序、后序遍历通过规律我们可以看到他们之间的位置分配 //伪代码 void solve(int preL,int inL,int n) { if(n == 0) return;//n等于0的时候什么都不做(n真的会右等于0的时候吗?为什么写他?)调用完了 之后右边没有元素,此时n等于0,进行判断正常结束进程 if(n == 1){p
62 0