最短路径算法的C#+access数据库实现

C# 专栏收录该内容
3 篇文章 1 订阅

最短路径算法的C#+access数据库实现

最短路的Dijkstra算法简介

1.Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。
2.算法
1)算法思想:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。
2)算法步骤:
a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则

数据库结构

1.在数据库中建立表如下结构:

IDnamenext_stationdis
1v12,3,46,3,1
2v251
3v32,4,102,2,7
4v4610
5v54,6,7,86,4,3,6
6v65,710,2
7v784,9
8v8103
9v95,82,2
10v107,93,8
…………………..

注:ID为节点的编号,next_station为与节点相连的其他节点,dis为权next_station列与dis采用字符串类型,以缩小数据库体积。在C#读数据库时将有进一步的分解字符串的操作。
2.创建节点类

 public class station
    {
        public int station_id = 0;
        private double lan = 0.0;
        private double lat = 0.0;
        public string station_name = null;
        public List<int> next_station = new List<int>();
        public List<double> distance_list = new List<double>();
        public double P = 0.0;
        public double T = 1000;
        public int f = -1;
        public station(int id, string name, List<int> next, List<double> dis)
        {
            this.station_id = id;
            this.station_name = name;
            this.next_station = next.ToList();            
            this.distance_list = dis.ToList();
        }     
        public station()
        { 

        }
    }

2.C#连接数据库并读取节点信息
2.1连接数据库

 private string DBlocation;
 private OleDbConnection dbconn; //数据库连接
 private OleDbDataAdapter da;
 private  List<station> tu = new List<station>();//站点链表
  dbconn = new OleDbConnection("provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\\tu.accdb;");
            dbconn.Open();
            if (dbconn.State == ConnectionState.Open)//判断数据库是否连接上
            {
                MessageBox.Show("已建立Access数据库连接!");
            }
            else
            {
                MessageBox.Show("未建立Access数据库连接!");
            }    

2.2读取数据库中的元素到tu list中

 private void readstation()///

        {

            List<int> next_station = new List<int>();
            List<double> next_dis = new List<double>();
            string next_stationstring ="";            
            string[] next_stationspilt = new string[10];
            string next_disstring ="";
            string[] next_disspilt = new string[10];
            string strSql = "select station.ID,station.name,station.next_station,station.dis from station";
            OleDbCommand sc1 = new OleDbCommand();
            sc1.CommandText = strSql;
            sc1.Connection = dbconn;            
            OleDbDataReader sda = sc1.ExecuteReader();           
            while (sda.Read())
            {

                next_stationstring =  sda.GetString(2);
                next_stationspilt = next_stationstring.Split(',');
                for(int i=0;i<next_stationspilt.Length;i++)
                {                   
                    next_station.Add(Convert.ToInt32(next_stationspilt[i]));

                }
                next_disstring = sda.GetString(3);
                next_disspilt = next_disstring.Split(',');//分割字符串
                for(int i =0;i<next_disspilt.Length;i++)
                {
                    next_dis.Add(Convert.ToDouble(next_disspilt[i]));
                }
                station aa = new station(sda.GetInt32(0), sda.GetString(1), next_station, next_dis);                
                tu.Add(aa);               
                next_station.Clear();
                next_dis.Clear();
            }           
        }

以上代码实现了数据库的连接与数据的载入,原理比较简单,就不赘述了。

3.算法实现

3.1改变P标号获取最短路径并给制定的点制定最优前节点

 private List<station> get_shortroute(int o,int d) ///改变P标号获取最短路径并给制定的点制定最优前节点
        {
            List<T> Top = new List<T>();
           // List<P> Pp = new List<P>();

            List<station> S = new List<station>();
            T tt = new T();
            int k = o;   

            station aa = new station();
            tu.ElementAt(o).P = 0;           
            S.Add ( tu.ElementAt(o));
            while (S.Count < tu.Count)           
            {  
                for (int i = 0; i < tu.ElementAt(k).next_station.Count; i++)
                {
                    int j = 0;
                    j = tu.ElementAt(k).next_station.ElementAt(i)-1;//取出下一个车站的ID
                    if (tu.ElementAt(k).distance_list.ElementAt(i) == 0)
                    {
                        return S;
                    }
                    if (tu.ElementAt(j).T > tu.ElementAt(k).P + tu.ElementAt(k).distance_list.ElementAt(i))
                    {
                        for (int l = 0; l < Top.Count; l++)
                        {
                            if (Top.ElementAt(l).station_id == tu.ElementAt(j).station_id)
                            {
                                Top.RemoveAt(l);
                            }
                        }
                        tu.ElementAt(j).T = tu.ElementAt(k).P + tu.ElementAt(k).distance_list.ElementAt(i);
                        tu.ElementAt(j).f = k;
                        Top.Add(new T((tu.ElementAt(j).station_id), tt.value = tu.ElementAt(j).T));
                    }
                   // tt.station_id = tu.ElementAt(j).station_id;
                   // tt.value = tu.ElementAt(j).T;

                    //tu.ElementAt().station_id;
                }
                Top.Sort(new Icp());//对Top中的元素进行排序
                tu.ElementAt(Top.ElementAt(0).station_id - 1).P = Top.ElementAt(0).value;                
                S.Add(tu.ElementAt(Top.ElementAt(0).station_id-1));               
                k = Top.ElementAt(0).station_id-1;
                Top.RemoveAt(0);
            }                        
            return S;           
        }

注:循环体内实现了标号的过程
类T为只包含ID和T标号的类以精简结构
Top.Sort(new Icp());
Top.RemoveAt(0);//对Top中的元素进行排序找出标号最小的,对应的点打到最优径路,后续不在对其比较用语句Top.RemoveAt(0);将其删除
比较器构造函数如下:

 public class Icp : IComparer<T>
    {

        public int Compare(T x, T y)
        {
            return x.value.CompareTo(y.value);
        }
    }

3.2逆向推导路径
上述函数只对有向赋权图进行了标号无法给出具体的最短路径下面的函数实现最短路径的逆向推导

 private List<int> get_route(int o, int d)
        {
            List <int> route =new List<int>();
            int k=d;
            route.Add(tu.ElementAt(k).station_id);
            while (tu.ElementAt(k).f!=-1 && tu.ElementAt(k).station_id-1!=o)//判断给出的点之间是否连通
            {
                route.Add(tu.ElementAt(k).f+1);
                k = tu.ElementAt(k).f ;
            }

            route.Reverse();
            return route;
        }

3.3路径的输出:
在Form中建立button按钮和text文本框
构造如下代码:

  private void button1_Click(object sender, EventArgs e)
        {
            tu.Clear();
            readstation();
            double dis ;
            dis = 0.0;
            List<int> route = new List<int>();
            get_shortroute(Convert.ToInt32(textBox1.Text) - 1, Convert.ToInt32(textBox2.Text)-1);
            route = get_route(Convert.ToInt32(textBox1.Text) - 1, Convert.ToInt32(textBox2.Text)-1); 
            if (route.Count == 1)
            {
                richTextBox1.Text = "没有连通请重新输入";
                MessageBox.Show("没有连通请重新输入");                
                return;
            }
            richTextBox1.Text = "";
            richTextBox1.Text = route.ElementAt(0).ToString();           
            for(int i=1;i<route.Count;i++)
            {
                richTextBox1.Text += ">>";
                richTextBox1.Text += route.ElementAt(i).ToString();


            }
            dis += tu.ElementAt(route.ElementAt(route.Count-1)-1).P;
            richTextBox1.Text = richTextBox1.Text + "\n" + "总费用为"+dis.ToString();
        }
    }
}

至此算法实现
后记:由于是初学者一些代码可能不够精炼,大神门多多指教
附上图片:
这里写图片描述

  • 6
    点赞
  • 2
    评论
  • 7
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

评论 2 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

xv740234390

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值