中科大地图导航

一, 科大西区地图的构建与表示:

(1)、物理地图的抽象表达

地图选择:科大西区地图

节点数:12

边数:15

 1

地点信息:地点名,时间,简介,街道名,街道长度(权值)

4

抽象地图:

2

3

 5

 6

    7

   8

9

10

 11

 

 

 

 

 

 

 

 

 

 

 

 

 

 


注释:该图为对科大地图抽象的结果。

各顶点信息(地点信息和边信息严格按原地图制作,故直接见地图):

1 :北门   2:圆盘岔路口  3:东路岔路口  4:核科学院  5:生命科学院  6:西区学生活动中心 7:校车站  8:电三楼   9:火灾重点实验室 10:南环路岔路口   11:国家同步实验室 。(计算机中表示顶点号要减去1)

(2)、地图信息的计算机信息表达

图文件节点代码(采用邻接表方式存储):

图信息定义于“节点定义.h”中,用于底层数据类型支持,其中重载了图的输入输出运算符,图中的节点和边的比较与赋值运算符等。

#define MAX_VERTEX_NUM 20

 

typedef struct InfoType    //边信息

{

         int     length;

         char*       name;

}InfoType;

 

typedef struct VertexType     //地点信息

{

         char*       name;      

         char*       time;

         char*       scribe;

         VertexType&operator =(VertexType& b);

}VertexType;

 

typedef struct ArcNode    //边

{

         int             adjvex;

         ArcNode *nextarc;

         InfoType *info;

         ArcNode&operator =(ArcNode& b);

}ArcNode;

 

typedef struct VNode    //图的邻接表

{

         VertexType* data;

         ArcNode *firstarc;

         VNode&operator=(VNode& a);

}VNode,AdjList[MAX_VERTEX_NUM];

科大地图的初始化(宏处理方式):

科大地图的初始化在“中科大地图.h”中完成,其中定义了ustc的namespace,在该namespace里有四个全区变量:

VertexType VexInfo[11];                     //节点信息矩阵

VNodenode[MAX_VERTEX_NUM];   //科大地图的邻接表

intUstcvexnum=0;                               //邻接表的顶点数

intUstcarcnum=0 ;                              //邻接表的边数

有四个全局函数:

voidInititaVex();                                 //初始化顶点信息

voidInititaNode();                               //初始化中科大地图邻接表

intFindword(char *p);                 //根据顶点名找到相应的顶点号

char*Findchar(char i);                //根据顶点号找到相应的顶点名

开始时,采用了很原始的复制粘贴的方式处理重复的数据,可是像这样有一定规模的数据,采用这样低级的方式处理,查询与修改时带来了很多的麻烦,于是设计了四个宏将处理简单化。

①  DECLEARE_ VEREXTYPE  宏:

使用于InititaVex()函数中,定义如下:

#defineDECLEARE_VEREXTYPE(dname,dtime,dscribe) \

        i= Findword(dname); \

VexInfo[i].name=dname; \

VexInfo[i].scribe=dtime;\

       VexInfo[i].time =dscribe;

于是有InititaVex()函数定义如下:

Void InititaVex()

{

int   i;

DECLEARE_VEREXTYPE(“北门”,”无“,”无“)

DECLEARE_VEREXTYPE("圆盘岔路口",”无“,”无“)

DECLEARE_VEREXTYPE("东路岔路口",”无“,”无“)

}

②  BEGIN_ARCMAP,ADD_ARCMAP,END_ARCMAP三宏:

这三宏使用于InititaNode()中,使用模式如下:

BEGIN_ARCMAP(…,…,…,..)

ADD_ARCMAP(…,…,…)

END_ARCMAP()

其定义如下:

#define   BEGIN_ARCMAP(sname,dname,aname,alength)\

                 i= Findword(sname);\

           node[i].data= &VexInfo[i];\

           PArcpresent= (ArcNode *) malloc(sizeof(ArcNode));\

           PArcpresent->adjvex = Findword(dname);\

           PArcpresent->nextarc = NULL;\

           PInfoType= (InfoType*)malloc(sizeof(InfoType));\

           PArcpresent->info = PInfoType;\

           PArcpresent->info->length =a length;\

           PArcpresent->info->name =aname;\

           node[i].firstarc= PArcpresent;\

           PArclast= PArcpresent;\

           Ustcarcnum++;

 

#define    ADD_ARCMAP(dname,aname,alength)\

PArcpresent = (ArcNode *)malloc(sizeof(ArcNode));\

           PArcpresent->adjvex = Findword(dname);\

           PArcpresent->nextarc = NULL;\

           PInfoType= (InfoType*)malloc(sizeof(InfoType));\

           PArcpresent->info = PInfoType;\

           PArcpresent->info->length = alength;\

           PArcpresent->info->name =aname;\

           PArclast->nextarc= PArcpresent;\

PArclast = PArcpresent;\

Ustcarcnum++;

 

#define   END_ARCMAP()\     

Ustcvexnum++;\

i = -1;

 

由以上三宏,InititaVex()函数定义如下:

void InititaNode() 

{

InititaVex();

inti;

ArcNode*PArcpresent,*PArclast;

InfoType*PInfoType;

BEGIN_ARCMAP(“北门”,”圆盘岔路口”,”济慈路”,10)

END_ARCMAP()

 

BEGIN_ARCMAP(”圆盘岔路口”,”北门”,”济慈路”,10)

           ADD_ARCMAP(“东路岔路口”,”东路”,21)

           …….

END_ARCMAP()

 

…..

}

于是在主函数里调用ustc:: InititaVex()函数即可完成对中科大地图的初始化。

二, 图的算法支持:

图的各种算法支持定义在CGraph类中,CGraph类声明文件如下:

#include "节点定义.h"

#define VERTEX_NUM 10

 

class CGragh 

{

private:

         AdjList vertices;

         int vexnum,arcnum;

          int Minlength[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //两顶点之间的最短距离数组

         char*Enumtrace[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //记录任意两点之间最短的路径

 

public:

         CGragh();

         CGragh(AdjList&a,int vex,int arc);

         virtual ~CGragh();

 

protected:

voidPrintArc(int i,int j);      //找到并打印直接相连的i,j顶点之间的路径。

         int FindMin(inta,int i,int& m);    //Dijkstra算法使用函数

         void Dijkstra(inti);

         void Dijkstrall();

 

public:

         intMinlengthPrint(int i,int j);       //返回顶点i与j之间的最短距离,并打印其路径。

         void PrintNode(inti);           //打印顶点i的信息

         void  TSPnum(int n);        //选择图中n个顶点,进行TSP求解

};

各种函数的说明均在其中,该类按如下过程完成对多种功能的支持:

                

(1)  构造函数读入过程:

构造函数,完成读入过程,较为简单,代码如下:

CGragh::CGragh(AdjList& a,intvex,int arc)

{

int i,j;

for(i=0;i<MAX_VERTEX_NUM;i++)                  //读入各种数据,邻接表

{

  vertices[i]= a[i];

}

arcnum = arc;

vexnum = vex;

for(i=0;i<MAX_VERTEX_NUM;i++)                 //初始化两记录数组

  for(j=0;j<MAX_VERTEX_NUM;j++)

  {

            Minlength[i][j]= -1;

            Enumtrace[i][j]= NULL;

  }

Dijkstrall();

}

(2)  Dijkstrall算法记录过程:

Dijkstra算法是图算法的核心,以后所有的各种操作均是以算法完成后的记录的数组为基础的,为这个算法支持类的核心,故详细列出讲解:

Dijkstrall()函数:

void CGragh::Dijkstrall()

{

int i;

for(i =0 ;i<vexnum;i++)

  Dijkstra(i);   //调用Dijkstra(int i)函数对各顶点进行运算

}

 

Dijkstra(int i)函数(函数写得匆忙,故变量命名没有太注意):

void CGragh::Dijkstra(int i)

{

       int k,j,minx,g=0;              //临时保存顶点的变量

       int temp,temp1,min;     //临时保存路径长度的变量

       char a[10],b[2];                     

 //临时保存各路径字符串,如”012”,就是从0号顶点到1号再到2号顶点。

       char *p;                     //用于生成最终要保存的路径字符串空间,更改其值。

//遍历生成i号顶点与其他顶点之间的最短距离,与最短路径字符串

      for(j = 1;j < vexnum;j++)

      {

            p= (char*) malloc(10 * sizeof(char));    

            //先在i顶点里找出其能直接到达,且记录数组未记录的最近顶点

 //FindMin函数找出a顶点能直接到达,且Minlength[i]没有记录

//的最近顶点,返回该顶点号(如果都已记录则返回-1),长度记录在//min里,稍后给出源码。

            if((minx = FindMin(i,i,min)) == -1)

            {

                     min= MAXINT;            //如周边都已记录,初始化min为MAXINT。

            }

            else

            {

                     *p= (char) i + 0x30;

                     *(p+1)= (char) minx + 0x30;

                     *(p+2)= '\0';

            }

            for(k=0;k< vexnum;k++)          //接下来,分析已记录的顶点

            {

                     if(k== i) continue;

                     if(Minlength[i][k]!= -1)    

                     {

                               temp= Minlength[i][k];           //长度加上已记录的顶点

                               strcpy(a,Enumtrace[i][k]);      //路径加上已记录路径

                               //找到该顶点里能直接到达,未记录且最近的顶点

                               if((g = FindMin(k,i,temp1)) == -1) continue; 

                               b[0]= (char) g + 0x30;

                               b[1]= '\0';

                               strcat(a,b);

                               temp+= temp1;

                               if(temp< min)                      //循环判断找到当前最近的顶点

                               {

                                        min= temp;

                                        minx= g;

                                        strcpy(p,a);

                               }

                     }

            }

                     //记录入数组

                     Minlength[i][minx]= min;

                     Enumtrace[i][minx]= p;

          }

}

当前的Dijkstra算法是我直接根据Dijkstra算法的文字描述所写的,算法上有很多的重复计算,造成较高的运算时间,还有很多需要改进的地方。

FindMin函数,该函数在上面已作说明,较为简单:

int CGragh::FindMin(int a,inti,int &m)

{

                inttemp = MAXINT,min = MAXINT;

                   ArcNode*PN1 = vertices[a].firstarc;

                   while(PN1)

                   {

                            if(Minlength[i][PN1->adjvex]== -1 &&

PN1->info->length < temp&&

PN1->adjvex != i)

                            {

                                     min= PN1->adjvex;

                                     temp= PN1->info->length;

                            }

                            PN1= PN1->nextarc;

                   }

                   if(min== MAXINT) return -1;

                   else

                   {

                            m= temp;

                            returnmin;

                   }

}

 

(3)  各种外部接口,完成相应功能:

intMinlengthPrint(int i,int j); //返回顶点i与j之间的最短距离,并打印其路径。

voidPrintNode(int i);              //打印顶点i的信息

void  TSPnum(int n);        //选择图中n个顶点,进行TSP求解

这三个功能函数都只需要直接调用(2)过程完成后记录数组即可,故源码不列出,具体实现见附件,在此只做简单说明,PrintNode函数输出操作在ArcNode定义里就已经重载,MinlengthPrint函数直接调用记录数组并输出即可。

TSPnum函数,由于时间原因,我是直接通过将选择顶点号全排列,通过最短长度数组找到其中最短的方式,但是通过贪心加动态规划算法可以将时间复杂度从O(N!)降至O(2^n),可以大大改进时间复杂度。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值