《数据结构》课程论文
设计题目 |
网络光纤铺设的最佳方案选择 |
课程名称 |
数据结构 |
姓 名 |
|
学号 |
|
专业名称 |
计算机应用技术 |
所在班级 |
|
指导教师 |
|
起止时间 |
|
评定成绩 |
|
一、 问题描述
需要在某个城市n个居民小区之间铺设网络光纤,假设任意两个居民小区之间均需要铺设光纤,则在这n个居民小区之间只需要铺设n-1条光纤即可形成一个网络,但由于地理环境不同,所需要的代价也不尽相同。本课程设计要求事先随机生成任意居民小区之间铺设网络光纤的代价,并将代价存入文件,然后设计一个最佳方案进行光纤铺设,使得既能连通所有小区之间的网络,又能使网络光纤铺设的代价最小,最终以图形形式输出所设计的最佳方案。
功能和结构设计
.kruskal算法:
(1)定义光纤网中的用户数,网的线路数,这里将光纤网的用户数定为不超过MAX=10;个。
(2)定义一个名为guangxian的类,公有成员中定义了类的
构造函数 guangxian();
析构函数 ~guangxian();
输入用户铺设光纤线路的数据的函数 void input();
输出用户铺设光纤线路的数据的函数 void output();
对铺设光纤线路最小生成树的算法函数 void minSpanTreeKruskal();
读出f1.txt文件数据的函数 void readfile();
保存f1.txt文件数据的函数 void writefile();
对铺设光纤线路进行随机选择的函数 void random();
保护成员中定义了类的
顶点数 verNum;
边数 arcNum;
存放定点的字符 verxs;
存放权值 arcs[MAX][MAX];
(3)在构造函数guangxian()中首先构造一个10*10的邻接矩阵,其中0为自己到自己的用户线路。888888为不存在的边。
(4)对minSpanTreeKruskal()函数进行类外定义,定义一个名为edges[MAX]的结构体变量,其数据成员begin,end,const,分别为一条线路的起点用户,终点用户和距离值。定义k并设初值为0用来统计生成树的边数,定义两个变量begin_set,end_set预存放某条边所处集合最后一个顶点的下标,如果begin_set!=end_set,若不相同,则说明在不同的子集中,选择此边作为一条新的分支,并合并两个子集,进入最小生成树的构造,令k++;若begin_set==end_set则进入for循环的下一次。
(5)最后利用input()中的for循环键入每条线路的起始用户点,终结用户点及线路上的距离值,用克鲁斯卡尔算法合成最小生成树。因为要求输入最小生成树合成的循环的网中的线路上的距离值必须为从小到大排列,所以采用冒泡排序后,再进入克鲁斯卡尔算法的for循环,最终循环输出每一条关键路径的起始用户点,终结用户点及线路上的距离值,并根据输入的单价求出所需的网络光纤的最佳选择方案下的铺设代价。
1. 模块分析
根据对模型的功能分析,该网络光纤铺设的设计可以具有以下功能:
①. 网络光纤铺设信息的输入;
②. 最小生成树信息的输出;
下面我们给出相应的功能模块图:
2. 抽象数据类型分析
verNum 用户总数(顶点总数);
arcNum 线路的总数(边的总数);
arcs[MAX][MAX] 邻接矩阵存储图结构;
s 边的距离值;
m,n; 分别表示要输入的始点和终点的字符
3. 功能分析
光纤铺设的输入
光纤铺设的输出
随机生成方案
铺设最佳方案
保存文件资料
二、 算法设计
1. 详细算法分析
(1)信息输入模块
cout<<"请输入居民个数(<=10):";
cin>>verNum;
cout<<"请输入可以铺设的光纤线路条数:";
cin>>arcNum;
cout<<"按字符形式依次输入各个用户名(如:abc):";
cin>>verxs;
for(int i=0;i
{
cout<<"请输入第"<
cin>>m;
cout<<" 终点:";
cin>>n;
cout<<" 距离:";
cin>>s;
for(int j=0;j
{
if(m==verxs[j])
x=j;
if(n==verxs[j])
y=j;
if(x!=888&&y!=888)
break;}
if(x==888||y==888)
{cout<<"该线路的起点用户或终点用户不存在,请重新输入!"<
--i;}
else
{ arcs[x][y]=s;
arcs[y][x]=s;}
x=y=888;}}
初始化矩阵各元素值
for(int i=0;i
for(intj=0;j
{
if(i==j)
arcs[i][j]=0;
else
arcs[i][j]=888888;}
输出邻接矩阵
for(i = 0; i
{
for(j= 0; j < areanum; j++)
{
cout<
}
cout<
}
(2)对edges[MAX]数组中的线路的距离值进行冒泡从小到大排序
k=0;
for(i=0;i
for(j=i+1;j
{
if(arcs[i][j]!=888888)
{
edges[k].cost=arcs[i][j];
edges[k].begin=i;
edges[k].end=j;
k=k+1;
}
}
for(i=0;i
for(j=i+1;j
if(edges[i].cost>edges[j].cost)
{
intt1,t2,t3;
t1=edges[i].cost;
t2=edges[i].begin;
t3=edges[i].end;
edges[i].cost=edges[j].cost;
edges[i].begin=edges[j].begin;
edges[i].end=edges[j].end;
edges[j].cost=t1;
edges[j].begin=t2;
edges[j].end=t3;
}
(3)建立最小生成树并输出结果
k=0; int xy=0;
for(i=0;i
{ //记录当前边所处集合最后一个顶点的下边
begin_set=set[edges[i].begin];
end_set=set[edges[i].end];
//若不相同,则说明在不同的子集中,选择此边作为一条新的分支
if(begin_set!=end_set)
{ //合并两个子集,表示已进入最小生成树
for(j=0;j
if(set[j]==begin_set)
set[j]=end_set;
cout<<"("<
"--"<
xy+=edges[i].cost;
++k;
if(k%5==4)
{cout<
cout<<" ";
}
}
三. 源程序代码
xq.h
#include
#include
#include
#include
#include
using namespace std;
const int MAX=10; //顶点数最多为10个
template
class guangxian
{
public:
guangxian();
~guangxian();
void input();
void output();
void minSpanTreeKruskal();
void writefile();
void readfile();
void random();
protected:
int verNum; //顶点数
int arcNum; //边数
string verxs; //存放定点的字符
T arcs[MAX][MAX]; //存放权值
};
xq1.cpp
#include"xq.h"
#include
template
guangxian
{
verNum=arcNum=0;
for(int i=0;i
for(int j=0;j
{
if(i==j)
arcs[i][j]=0;
else
arcs[i][j]=888888;
}
}
template
guangxian
{
verNum=arcNum=0;
}
template
voidguangxian
{
int x=888; //x、y分别表示始点和终点的小标
int y=888; //x、y等于888888时表示没有找到始点、终点
char m,n; //分别表示要输入的始点和终点的字符
float s; //居民区间的距离
int k=888888; //权值,等于888888时,表示无穷大
cout<<"请输入居民个数(<=10):";
cin>>verNum;
cout<<"请输入可以铺设的光纤线路条数:";
cin>>arcNum;
cout<<"按字符形式依次输入各个用户名(如:abc):";
cin>>verxs;
for(int i=0;i
{
cout<<"请输入第"<
cin>>m;
cout<<" 终点:";
cin>>n;
cout<<" 距离:";
cin>>s;
for(int j=0;j
{
if(m==verxs[j])
x=j;
if(n==verxs[j])
y=j;
if(x!=888&&y!=888)
break;
}
if(x==888||y==888)
{
cout<<"该线路的起点用户或终点用户不存在,请重新输入!"<
--i;
}
else
{
arcs[x][y]=s;
arcs[y][x]=s;
}
x=y=888;
}
}
template
voidguangxian
{
int i,j;
cout<<" ";
for(i=0;i
cout<<" "<
cout<
for(i=0;i
cout<<"["<
cout<
for(i=0;i
{
cout<
for(j=0;j
{
if(arcs[i][j]==888888)
cout<
else
cout<
}
cout<
}
}
template
voidguangxian
{
struct
{
int begin; //一个顶点下标
int end; //另一个顶点下标
int cost; //边的权值
}edges[MAX]; //按权值从小到大排序
int begin_set,end_set; //预存放某条边所处集合最后一个顶点的下标
int i=0,j=0,k=0;
int set[MAX]; //辅助数组
for(k=0;k
edges[k].cost=888888;
for(k=0;k
set[k]=k;
k=0;
for(i=0;i
for(j=i+1;j
{
if(arcs[i][j]!=888888)
{
edges[k].cost=arcs[i][j];
edges[k].begin=i;
edges[k].end=j;
k=k+1;
}
}
for(i=0;i
for(j=i+1;j
if(edges[i].cost>edges[j].cost)
{
int t1,t2,t3;
t1=edges[i].cost;
t2=edges[i].begin;
t3=edges[i].end;
edges[i].cost=edges[j].cost;
edges[i].begin=edges[j].begin;
edges[i].end=edges[j].end;
edges[j].cost=t1;
edges[j].begin=t2;
edges[j].end=t3;
}
k=0;
int xy=0;
for(i=0;i
{ //记录当前边所处集合最后一个顶点的下边
begin_set=set[edges[i].begin];
end_set=set[edges[i].end];
//若不相同,则说明在不同的子集中,选择此边作为一条新的分支
if(begin_set!=end_set)
{ //合并两个子集,表示已进入最小生成树
for(j=0;j
if(set[j]==begin_set)
set[j]=end_set;
cout<<"("<
"--"<
xy+=edges[i].cost;
++k;
if(k%5==4)
{
cout<
cout<<" ";
}
}
}
cout<
cout<
float price;
double total;
cout<<"请输入每米光纤的价格:";
cin>>price;
total=xy*price;
cout<
}
template
voidguangxian
{
ifstream infile("c:\\f1.txt",ios::in);
if(!infile)
{
cerr<<"openerror!"<
exit(1);
}
infile>>verNum;
infile>>arcNum;
infile>>verxs;
for(int i=0;i
for(int j=0;j
infile>>arcs[i][j];
cout<<"文件已读出!"<
infile.close();
}
template
voidguangxian
{
ofstream outfile("c:\\f1.txt",ios::out|ios::trunc);
if(!outfile)
{
cerr<<"openerror!"<
exit(1);
}
outfile<
outfile<
outfile<
for(int i=0;i
for(int j=0;j
outfile<
cout<<"文件已保存!"<
outfile.close();
}
template
voidguangxian
{
struct
{
int begin; //一个顶点下标
int end; //另一个顶点下标
int cost; //边的权值
}edges[MAX]; //存放边资料
int begin_set,end_set; //预存放某条边所处集合最后一个顶点的下标
int i=0,j=0,k=0;
int set[MAX]; //辅助数组
for(k=0;k
edges[k].cost=888888;
for(k=0;k
set[k]=k;
k=0;
for(i=0;i
for(j=i+1;j
{
if(arcs[i][j]!=888888)
{
edges[k].cost=arcs[i][j];
edges[k].begin=i;
edges[k].end=j;
k=k+1;
}
}
k=0;
int xy=0;
for(i=0;i
{ //记录当前边所处集合最后一个顶点的下边
begin_set=set[edges[i].begin];
end_set=set[edges[i].end];
//若不相同,则说明在不同的子集中,选择此边作为一条新的分支
if(begin_set!=end_set)
{ //合并两个子集,表示已进入最小生成树
for(j=0;j
if(set[j]==begin_set)
set[j]=end_set;
cout<<"("<
"--"<
xy+=edges[i].cost;
++k;
if(k%5==4)
{
cout<
cout<<" ";
}
}
}
cout<
cout<
float price;
double total;
cout<<"请输入每米光纤的价格:";
cin>>price;
total=xy*price;
cout<
}
xq2.cpp
#include"xq1.cpp"
#include
void main()
{
system("Color 3E");
guangxian
int num;
int b;
while (1)
{
cout <<
"┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓";
cout <<
"┃ →→→→ ><(((:> 欢迎 使 用 <:)))>< ←←←← ┃";
cout <<
"┃ ┃";
cout <<
"┃◇◇◇◇◇ 网络光纤铺设最佳方案选择 ◇◇◇◇◇┃";
cout <<
"┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫";
cout <<
"┃*********** 用户菜单(1~7) ***********┃";
cout <<
"┃**************** ****************┃";
cout <<
"┃ ┃";
cout <<
"┃◇◇◇◇◇◇ ★ 1. 光钎铺设输入 ★ ◇◇◇◇◇◇┃";
cout <<
"┃◇◇◇◇◇ ★ ★ 2. 光钎铺设输出 ★ ★ ◇◇◇◇◇┃";
cout <<
"┃◇◇◇◇ ★ ★ 3. 读取文件资料 ★ ★ ◇◇◇◇┃";
cout <<
"┃◇◇◇◇◇ ★ ★ 4. 保存文件资料 ★ ★ ◇◇◇◇◇┃";
cout <<
"┃◇◇◇◇◇◇ ★ 5. 铺设最佳方案 ★ ◇◇◇◇◇◇┃";
cout <<
"┃ 6. 随机生成方案 ┃";
cout <<
"┃ 7. 退出 ┃";
cout <<
"┃***************** *****************┃";
cout <<
"┃*********** ***********┃";
cout <<
"┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛";
cout << "<请选择操作()>:";
cin>>num;
switch(num)
{
case 1:
mg.input();
system("pause");
system("cls");
break;
case 2:
mg.output();
system("pause");
system("cls");
break;
case 3:
mg.readfile();
system("pause");
system("cls");
break;
case 4:
mg.writefile();
system("pause");
system("cls");
break;
case 5:
mg.minSpanTreeKruskal();
system("pause");
system("cls");
break;
case 6:
mg.random();
cout<<"是否需要保存(1/0)?"<
cin>>b;
if(b==1)
mg.writefile();
system("pause");
system("cls");
break;
default:
cout<<"感谢您的使用"<
Sleep(28880);//休眠2秒钟
exit(1);
}
}
}
三、 课程设计总结
经过两个星期的不懈努力,数据结构课程设计终于落幕。我这次的课程设计的题目是《网络光纤铺设的最佳方案选择》,即使用 克鲁斯卡尔算法 得到所需要的最小的生成树。在整个设计过程中,自己从刚开始简单的构思算法思路的大致框架,直到最后使得整个算法顺利的得以实现。期间遇到的问题、错误多不甚数,然经过无数次的调试分析,最终一一得以圆满解决。
在这两个星期里,自己可谓是感慨万分。的确,从选题到定稿,从理论到实践,在整整两星期的日子里,可以说得是苦多于甜,但是自己却能够在这短短的两个星期里学到很多很多的的东西,不仅可以巩固了以前所学过的知识,加深了对课本知识点的理解。而且学到了很多在书本上所没有学到过的知识,能够说是收获颇丰。
通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,从实践中验证理论,从而提高自己的实际动手能力和独立思考的能力。当然,在设计的过程中遇到许许多多的问题,可以说得是困难重重,毕竟这是一次课程设计,需要掌握的知识面比较广,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固,通过这次课程设计之后, 一定把以前所学过的知识重新温故。在设计中,vc ++6.0使用的也更加的牢固,了解的也更加深刻。
这次课程设计已经结束了,对于我自己,对本次课程设计我的感受很深,在这个过程中,我也曾经因为实践经验的缺乏失落过,也为毫无头绪而烦恼,也曾经为调试的成功实现而手舞足蹈。呵呵,让自己在本次课程设计中感受了一番大起大落,使自己从中明白了,做成功一件事,是需要付出和汗水的。天下无难事只怕有心人,只要自己坚定信念,成功也只在咫尺之间。当然,我们也不能满足于现有的水准,否则就会停滞不前,要知道学海无涯,仍需我们努力学习。所以,在以后的时间里,我会利用更多时间去上机实验,加强自学的能力,多编写程序,相信不久后我的编程能力会有所提高能设计出更多的更有创新的作品!
四、 参考资料
1.王红梅 《数据结构》(C++版) 清华大学出版社
2.杨进才 《C++语言程序设计教程》(第二版) 清华大学出版社