数据结构课程设计报告概述.docx
《数据结构课程设计报告概述.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计报告概述.docx(27页珍藏版)》请在冰豆网上搜索。
数据结构课程设计报告概述
课程设计报告
题目:
中国行政区域图染色与信息查询
课程名称:
数据结构课程设计
专业班级:
计算机科学与技术班
学号:
姓名:
指导教师:
报告日期:
2012年10月10日
计算机科学与技术学院
2系统设计方案的研究
3系统的设计及实现
1绪言
数据结构是计算机科学技术与信息安全等专业的一门重要专业基础课,牢固掌握数据结构的基础知识,熟练地运用数据结构的思想与技术方法解决实际应用问题是是本课程学习的基本任务与目标。
而课程设计是实现这一学习目标的重要环节和组成部分。
通过课程设计的训练,使学生加深对数据结构知识的理解,牢固掌握其应用方法,并合理灵活地解决一定实际问题,增强和提高综合分析问题与解决问题的能力。
在本次课程设计中我选择了“中国行政区域图染色与信息查询”作为我的题目,这个题目要求设计者掌握图的存储结构与基本算法以及数据结构的基本概念和思想,解决较复杂的基于图模型的实际问题。
我将每个行政区域作为一个顶点,邻接矩阵作为主要存储结构,邻接矩阵中邻接关系用边的权值表示,用回溯法设计染色算法,用典型求解最小生成树的Prim算法解决最小费用通信网规划问题。
邻接矩阵信息以及各省份信息分别保存在文件中。
2系统设计方案的研究
2.1系统的控制特点与性能要求
系统性能要求:
(1)从互联网或相关资料获取可靠的行政区域及其地理数据,有关数据与信息
以文件形式存储,用无向网建模上述问题并以文件保存。
(2)图形方式显示上述图模型与求解结果。
(3)界面友好,具有对各省份相关信息的查询功能。
系统控制特点:
由于本系统要求图形化显示求解结果,故系统需要有较好的用户界面方便用户操作以及过程的显示。
因此在界面设计上一定要简明易懂,易于操作。
当用户误操作后系统应作出相应的提示和错误处理,使得操作能够继续。
2.2系统设计方案选择及分析
系统要求使用图形方式显示染色过程,所以我选择MFC编程来编写一个基于Windows操作系统的应用程序。
MFC是微软封装了的API,是面向对象程序设计与Applicationframework的完美结合,它将传统的API进行了分类封装,并且创建了程序的一般框架,便于设计者很快生成能在Windows操作系统下运行的可视化应用程序。
MFC开发基本使用的是C++语言,同时也完全兼容C语言编写的功能函数,这对于像我这种熟悉C语言编程的人有较大便利。
开发环境我选择的是MicrosoftVC++6.0。
VisualC++6.0由Microsoft开发,它不仅是一个C++ 编译器,而且是一个基于Windows操作系统的可视化集成开发环境。
VisualC++6.0由许多组件组成,包括编辑器、调试器以及程序向导AppWizard、类向导ClassWizard等开发工具。
在应用程序窗口设计方面,我选择对话框的编程,窗口设计如图2.1所示。
图2.1窗口结构设计
在主窗口中进行地图的显示以及进行与图形相关的操作,信息查询显示则在新窗口中进行,这样安排使得不同的操作各自独立进行,防止了相互间的干扰,同时也简化了单个函数的长度,使得程序条理更加清晰,也方便用户的使用。
程序采用模块化设计方案,即先设定好主程序,子程序,子过程框架,并定义好各个框架之间的输入,输出链接关系,逐步求精得到以功能块为单位的算法描述。
模块化设计具有降低程序复杂度,使程序设计、调试和维护等操作简单化的优点。
在主窗体中设有5个功能按钮,分别对应程序5个功能。
按钮事件分别对应窗口类中的5个成员函数,关系如图2.2所示。
图2.2主窗口类中功能实现函数
除了窗口类的成员函数,我还自定义了一些辅助功能函数,这些函数在新建的头文件my_h.h中进行声明。
辅助功能函数有:
StatusInitQueue(LinkQueue&Q);//初始化队列
StatusEnqueue(LinkQueue&Q,CPoint&e);//入队列
CPointDequeue(LinkQueue&Q,CPoint&e);//出队列
BOOLQisEmpty(LinkQueue&Q);//判断队列是Q否为空
BOOLInitRelation(intv[][32]);//载入邻接矩阵到intv[][]
voidSetColor(intlin[][32],intv[]);//对每个省份进行颜色分配
voidInitPoint(CPointp[]);//初始化各省份坐标
voidInitProName(CStringn[]);//在省份查询窗口中对各省份名称初始化
voidInitProInfo(proinfopro_i[]);//载入省份信息到pro_i[]
至此,整个程序框架已经完成了,如图2.3所示。
图2.3模块化程序框架
在文件方面,我将邻接矩阵直接存放在linjiejuzhen.txt文件中,初始化时直接将文件中内容读取到二位整形数组中,这样大大简化了读文件操作,同时也免去了邻接矩阵初始化时不必要的操作。
与常规的邻接矩阵不同的是,我将邻接矩阵中表示结点相邻的1直接用两结点的权值代替,这使得构建无向网操作得以简化同时也提高了文件的利用率。
在另一个文件proinfo.txt中保存着各个省份信息,在读取信息时一次将所有信息读取到一个pro_info结构体数组中,这样便于数据的处理。
3系统设计及实现
3.1染色模块的设计
首先在功能函数OnZhuose()中定义一个二维整型数组linjie[32][32]来存放邻接矩阵,由四色问题的证明可知“任何一张地图只用四种颜色就能使具有共同边界的国家着上不同的颜色”。
故我们可定义一个整形数组pro_color[33]来存放对每个省份分配的颜色,颜色用整数表示,1表示洋红色
2表示黄色
,3表示青色
,4表示绿色
。
在将邻接矩阵数据载入后,我先将矩阵中的非0值全部改成1,即将二维数组linjie[][]变成严格意义上的邻接矩阵,再使用SetColor()函数对数组数据进行分析同时在pro_color[]中分配各省份的颜色值。
在SetColor()函数中,定义有三个变量area(区域号),colornum(染色号),k(已着色区域号)。
首先将1号区域染1色(即pro_color[1]=1),对当前区域进行判断,如果k区域与当期区域不相邻或相邻而不重色则对下一个区域进行判断。
如果相邻且重色则改变colornum的值。
流程图如图3.1所示。
图3.1SetColor()流程图
对各省颜色分配完后就进行地图染色,在OnZhouse()函数中定义了一个CPoint类型的数组并用进行初始化,在数组中保存着各个省份省会城市在地图中的坐标信息,每个省份的染色就从这个坐标开始。
地图染色使用的回溯法。
定义一个个队列Q,队列中结点在头文件my_h.h中定义如下:
typedefstructQNode{
CPointdata;
structQNode*next;
}QNode,*QueuePtr;
//定义一个队列
typedefstruct{
QueuePtrfront;
QueuePtrrear;
}LinkQueue;
Q中保存即将染色的点。
开始绘色时先将各省初始化的坐标入队,再进行循环。
循环开始时定义一个CPoint变量pt,Q进行出队操作,pt保存出队结果。
对pt进行判断,如果该点颜色为白色则将该点染色,并依次判断该点的上下左右四个点,如果哪个点颜色为白色则将该点入队。
流程图如图3.2所示。
图3.2单个省份染色流程
3.2管道铺设模块设计
在OnButton3()函数中,首先进行邻接矩阵的载入以及各省坐标的初始化。
管道铺设分为两个步骤:
绘出无向网和求出最小生成树。
绘制无向网相对简单,只需遍历整个邻接矩阵,对相邻的两个省份的省会坐标之间绘制一条线即可。
求最小生成树我采用Prim算法,这也是较为经典的求最小生成树算法。
为实现这个算法需附设一个辅助结构数组closedge,结构体在头文件my_h.h中定义如下:
typedefstruct{
intadjvex;//最小代价边依附的点
intlowcost;//最小代价边的权
}CE;
还要将无向网中不相邻的两个顶点距离设为无穷大,无穷大为头文件my_h.h中定义的一个宏:
#defineINFINITY32768
Prim算法类C语言表示如下:
voidMiniSpanTree_PRIM()
{
CEclosedge[MAX_VERTEX_NUM];
k=0;
for(j=0;jif(j!
=k)closedge[j]={k,linjie[k][j]};
closedge[k].lowcost=0;//初始距离为0
for(i=1;i{
k=minimum(closedge)//求出T的下一个结点:
第k结点
MoveTo(pro_point[k]);
LineTo(pro_point[closedge[k].adjvex]);//绘出生成树的边
closedge[k].lowcost=0;//第k顶点并入U集
for(j=0;jif(linjie[k][j]!
=0&&linjie[k][j]//新顶点并入U后重新选择最小边
closedge[j].adjvex={k,linjie[k][j]};
}
}//MiniSpanTree
3.3省份信息查询模块设计
省份查询是在一个新弹出的对话框中进行操作,在窗口类InfoDlg的初始化函数中对下拉列表载入各省份条目,用户选择一个条目后点击“确定”按钮显示该省份信息。
存放单个省份信息的结构体在头文件my_h.h中的定义如下:
typedefstruct
{
charshenghui[10];//省会
charquhao[5];//区号
floatrenkou;//人口
charweizhi[50];//位置
floatmianji;//面积
}proinfo;
在函数OnOK()中首先定义一个CString数组info[5]来保存每一项的显示内容,一个proinfo结构数组pro_i[32]保存从文件读入的各省份信息。
读取用户选择的省份条目,将该省份的信息格式化写入到info中再将info内容依次显示在对话框中。
每次显示前进行清屏操作擦除上次显示的内容。
3.4其他模块设计
还原模块的的功能主要是使程序回到最初状态。
用户在管道铺设后已将各省份特征坐标点染色,这样染色操作就无法进行,再者用户在染色操作过程中如果出现程序异常或者是将已染色区域擦除,就可以通过还原使程序回到初始状态而重新进行操作。
还原函数的实现是将空白地图重新载入窗口,覆盖原先的图像即可。
关于模块显示系统信息以及作者信息。
点击主窗口中的“关于”按钮即弹出一个对话框,这个对话框是根据MFC自动生成的关于窗口修改而成的。
3.5其他设计
为了程序设计的方便以及程序使用中具有良好的操作性,在程序中我还加入了一些其他设计元素。
(1)在头文件中定义的宏和typedef声明:
#defineOK1//用于函数返回值
#definePRO_N32//地图中需处理省份个数
typedefintStatus;
(2)为了使得邻接关系中省份表示更加直观,我依照矩阵中存储的省份顺序定义了一个枚举类型:
enumprovince
{
beijing,//北京
tianjin,//天津
hebei,//河北
shanxi,//山西
neimeng,//内蒙古
liaoning,//辽宁
jilin,//吉林
heilongjiang,//黑龙江
shanghai,//上海
jiangsu,//江苏
zhejiang,//浙江
anhui,//安徽
jiangxi,//江西
shandong,//山东
henan,//河南
hubei,//湖北
hunan,//湖南
guangdong,//广东
guangxi,//广西
hainan,//海南
chongqing,//重庆
sichuan,//四川
guizhou,//贵州
yunnan,//云南
xizang,//西藏
shaanxi,//陕西
gansu,//甘肃
ningxia,//宁夏
xinjiang,//新疆
qinghai,//青海
taiwan//台湾
};
这样一来如果想读取邻接矩阵中某个省份的数据就可以直接将省份名作为数组下标,如判断湖北省与湖南省相邻关系则判断linjie[hubei][hunan]的值。
(3)在窗口类CMyDDlg中定义了两个整形成员变量:
intis_colored;//判断染色是否完成
intis_tubed;//判断管道铺设是否完成
如果is_colored等于1则表示一次染色完成,反之则表示没进行染色,同理如果is_tubed等于1则表示管道已铺设,反之则表示没有铺设管道。
在CMyDDlg类的构造函数中将两个变量均置为0,着色函数开始时先判断is_colored和is_tubed的值,若有一个不为0则表示当前无法染色,程序会提示用户先进行还原操作。
着色程序最后将is_colored置为1,管道铺设函数最后将is_tubed置为1。
还原函数最后将is_colored和is_tubed都置为0。
4系统结果分析
系统运行后结果如图4.1所示。
图4.1系统运行最初界面
点击“开始着色”按钮后运行结果如图4.2所示。
图4.2染色进行时
染色完成后结果如图4.3所示。
图4.3染色结果
再点击“铺设管道”按钮进行管道铺设,如图4.4所示。
图4.4管道铺设结果
点击“还原”按钮使程序回到初始状态,如图4.5所示。
图4.5还原结果
程序初始化后再进行管道铺设操作,如图4.6所示。
图4.6程序初始化后进行管道铺设
点击“省份信息”按钮显示信息查询窗口,如图4.7所示。
图4.7省份信息查询窗口
选择省份并点击“确定”按钮显示相应省份信息,如图4.8所示。
图4.8查询省份信息
点击“关于”按钮显示系统和作者信息,如图4.9所示。
图4.9关于
VC++6.0中类、资源和源文件的组织如图4.10所示。
图4.10IDE中类、资源和源文件组织
由以上结果可以看出该系统可以得到在所给条件下的正确结果,并且完成了系统所要求的功能。
在系统运行过程中没有出现死机或者自动关闭的情况。
然而在测试过程中我也发现了一些不尽如人意的地方,如当其他窗口覆盖程序窗口后,染色区域和管道铺设结果会被擦除;染色过程中用户只能进行等待,如果鼠标在窗口内点击可能会使得染色停止;在Windows7操作系统下程序运行变慢,而且窗口大小比例发生了变化,图4.11所示。
图4.11Windows7环境下程序初始界面
5总结
当初选择这个题目感觉这个题目比较有趣,实际在做的过程中才发现有很多东西需要学习。
就拿MFC来说,MFC本身十分庞杂,学习起来有一定难度,我就有选择地学习,先学习基本的对系统的设计有用的方面,经过一段时间的自学算是对MFC入门了,但是这只是很表面的东西,如果以后要做功能更复杂的系统需要更加深入地学习。
再有平时学习数据结构中的图和图的算法仅仅是停留在概念层面,自己从来没有真正实现过,这次就我自己进行实现需要透过概念将理论转化为实际可行的代码,这其中就有思想的转化,也让我对数据结构基本理论有了更直观的理解。
这次的系统设计在正确完成了所要求的功能之外,我认为还有以下优点:
(1)界面简洁直观。
在程序设计之初我计划使用带有菜单的窗口作为主窗口,但是加入菜单后使得程序复杂度和操作性都增加,而且类较多,使得程序结构变得松散,最后换成对话框编程以上问题得以解决。
(2)操作简单。
相关操作就简化为几个按钮,用户操作方便了很多。
而且用户只是使用鼠标操作,这在一定程度上减少了误操作,提高了程序的健壮性。
当然,此次课程设计还有一些不足的地方:
(1)显示的问题。
当窗口被其他窗口遮盖后会将染色和管道铺设结果擦除,需要还原后重新绘制。
(2)数据是单向的。
系统只提供了数据的查询显示而没有修改、删除功能,缺乏与用户的交互。
在染色颜色设定和管道设定方面也没有给用户提供选择的余地。
(3)染色相对较慢。
每个省份从一点开始逐点向外染色花费时间较长,这在运行过程中就可以明显体现出来,而且程序没有提供中断染色功能,染色时用户只能等待。
(4)由于程序是在WindowsXP系统下编译调试的,在Windows7系统中运行时窗口大小比例以及运行效率上都发生了一点偏差。
以上问题是我现有知识不能解决的,在以后学习中我还需要不断学习,努力提高自己编程能力,做出功能更加完善,实用性更强的系统。
参考文献
[1]严蔚敏,吴伟民.数据结构.北京:
清华大学出版社,1997.
[2]曹计昌,卢萍,李开.C语言程序设计.北京:
科学出版社,2008.
[3]孙鑫.VC++深入详解.北京:
电子工业出版社,2006.
[4]余祥宣,崔国华,邹海明.计算机算法基础(第三版).武汉:
华中科技大学出版社,2006.
[5]URL:
附录部分代码
//从文件中载入邻接矩阵
BOOLInitRelation(intv[][32])
{
FILE*fp;
inti,j;
if((fp=fopen("linjiejuzhen.txt","rt"))==NULL)
{
returnFALSE;
}
for(i=0;i{
for(j=0;jfscanf(fp,"%d\t",&v[i][j]);
fscanf(fp,"\n");
}
fclose(fp);
returnTRUE;
}
//从文件中载入各省份信息
voidInitProInfo(proinfopro_i[])
{
FILE*fp;
fp=fopen("proinfo.txt","rt");
for(inti=0;i<32;i++)
{
fscanf(fp,"%s%s%f%s%f\n",pro_i[i].shenghui,pro_i[i].quhao,&pro_i[i].renkou,pro_i[i].weizhi,&pro_i[i].mianji);
}
fclose(fp);
}
//着色函数
voidCMyDDlg:
:
OnZhuose()
{
intlinjie[32][32],pro_color[33];//邻接矩阵和各省份所分配的颜色
inti,j;
CClientDCdc(this);
CPointpro_point[32],point[4];//各省份标记坐标,point数组保存点的上下左右四点
COLORREFm_color,m_color1,ColorBox[4];
memset(pro_color,0,sizeof(pro_color));
if(is_tubed==1||is_colored==1)//判断能否进行染色
{
MessageBox("请先还原!
");
return;
}
InitRelation(linjie);//载入矩阵
InitPoint(pro_point);//初始化各省份标记坐标
for(i=0;i<32;i++)//对矩阵进行变换
for(j=0;j<32;j++)
linjie[i][j]=(linjie[i][j]>0)?
1:
0;
SetColor(linjie,pro_color);//为每个省份分配颜色
ColorBox[0]=RGB(255,0,255);//染色所需的四种颜色
ColorBox[1]=RGB(255,255,0);
ColorBox[2]=RGB(0,255,255);
ColorBox[3]=RGB(0,255,0);
for(i=0;i<32;i++)//地图开始染色
{
switch(pro_color[i+1]){
case1:
m_color=ColorBox[0];break;
case2:
m_color=ColorBox[1];break;
case3:
m_color=ColorBox[2];break;
case4:
m_color=ColorBox[3];break;
default:
m_color=RGB(0,0,0);break;
}
LinkQueueQ;
InitQueue(Q);
Enqueue(Q,pro_point[i]);
while(!
QisEmpty(Q))
{
CPointpt;
Dequeue(Q,pt);
if(GetPixel(dc,pt.x,pt.y)==RGB(255,255,255))
{
SetPixel(dc,pt.x,pt.y,m_color);
point[0].x=pt.x+1;
point[0].y=pt.y;
point[1].x=pt.x-1;
point[1].y=pt.y;
point[2].y=pt.y+1;
point[2].x=pt.x;
point[3].y=pt.y-1;
point[3].x=pt.x;
for(intj=0;j<4;j++)
{
m_color1=GetPixel(dc,point[j].x,point[j].y);
if(m_color1==RGB(255,255,255))
{
Enqueue(Q,point[j]);
}
}
}
}
}
is_colored=1;//is_colored设为1表示完成