数据结构课程设计Word格式文档下载.docx
《数据结构课程设计Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计Word格式文档下载.docx(14页珍藏版)》请在冰豆网上搜索。
一、分析题目要求
1、在这个课程设计中,我做的是并查集。
主要实现以下的功能:
1)初始化
2)合并结合
3)查找节点所在集合
4)相关应用
初始化:
把每个点所在集合初始化为其自身。
通常来说,这个步骤在每次使用该数据结构时只需要执行一次,无论何种实现方式时间复杂度均为O(N)。
查找:
查找元素所在的集合,即根节点。
合并:
将两个元素所在的集合合并为一个集合。
通常来说,合并之前,应先判断两个元素是否属于同一集合,这可用上面的“查找”操作实现。
为了在这个程序实现中更好地表现出相关功能,我用了一个具体的例子,也即是判断多个城市之间的并查集,并求出不同城市的距离长短。
2、各个函数命名,包含的参数,返回值类型
intmenu()//函数主菜单
voidxin_input()//第二级菜单
boolcmp(nodep1,nodep2)
//并查集
voidset(intx)//初始化
intfind(intx)//寻找数据的共同祖先
voidUnion(intx,inty)//合并函数
//算法
voidKruskal()//Kruskal算法
intprim()//prim算法
voidShortestPath_DIJ(intx,inty)//Dijkstra算法
voidShortestPath_FLOYD()//Floyd算法
voidshuru()//接收函数(接收输入的数据)
voidchaxun()//查询函数
//功能函数
voidchaxun_func()
voidjudge()
intmain()//主函数
3、程序的运行
二、解题思路
1、单链表实现
一个节点对应一座城市,在同一个集合中的节点串成一条链表就得到了单链表的实现。
在集合中我们以单链表的第一个节点作为集合的代表元。
于是每个节点x(x也是城市的编号)应包含这些信息:
指向代表元即表首的指针head[x],指向表尾的指针tail[x],下一个节点的指针next[x]。
2、两大优化
第一个优化是启发式合并。
在优化单链表时,我们将较短的表链到较长的表尾,在这里我们可以用同样的方法,将深度较小的树指到深度较大的树的根上。
这样可以防止树的退化,最坏情况不会出现。
Find-Set(x)的时间复杂度为O(logN),PROBLEM-Relations时间复杂度为O(N+logN(M+Q))。
SUB-Link(a,b)作相应改动
第二个优化是路径压缩。
它非常简单而有效。
如图所示,在Find-Set
(1)时,我们“顺便”将节点1,2,3的父节点全改为节点4,以后再调用-Find-Set
(1)时就只需O
(1)的时间。
三、调试分析
由于此程序实现的功能较为简单,故在调试过程中也没遇到很大的问题。
主要的问题在于着手写代码的时候,由于不熟悉及很多算法未接触过,故陷入了无从下手的境地。
但最后通过搜索大量的资料终于解决。
期间用到的测试数据是多组邻接矩阵,没有发现bug;
对于算法的不足之处,主要是时间复杂度过大,代码未能很好优化,另外对于改进的设想,也就是前面提到的两大优化,但由于自己未能实现,故只好作罢了。
所以,此次最大的感受就是自己的知识基础很薄弱,而且对于很多思维性和逻辑性要求很高的东西自己难以理解。
所以自己深知要加强这方面的锻炼。
更为自己过去一学期没能好好掌握的知识而感到痛心,有机会一定要补回来吧。
四、附录
带注释的源程序。
#include<
stdio.h>
string.h>
iostream>
algorithm>
#include<
windows.h>
usingnamespacestd;
intn=0;
inta[100][100];
intmenu()
{
intm;
printf("
并查集\n"
);
________________________________\n\n"
1输入城市之间的信息\n"
2判断是否能构成一个并查集\n"
3查询信息\n"
4退出\n"
请输入所选功能1--4\n"
scanf("
%d"
&
m);
returnm;
}
voidxin_input()
system("
cls"
1遍历所有城市的并查集\n"
2查询两个城市之间的距离\n"
3退出\n"
//以下为克鲁斯卡尔算法
typedefstructnode//构造一个结构体,两个城市可以看成起点和终点,之间的路道可以看成一个边
intst;
//起点
inted;
//终点
intdis;
//距离
}node;
nodep[1000];
intpre[1000],rank[1000];
returnp1.dis<
p2.dis;
//下面三个函数是并查集,其作用是检验当一条边添加进去,是否会产生回路
voidset(intx)
pre[x]=x;
//初始化
rank[x]=0;
intfind(intx)//找到这个点的祖先
if(x!
=pre[x])
pre[x]=find(pre[x]);
returnpre[x];
voidUnion(intx,inty)//将这两个添加到一个集合里去
x=find(x);
y=find(y);
if(rank[x]>
=rank[y])
pre[y]=x;
rank[x]++;
else
voidKruskal()//
intans=0,i,j,k=0;
for(i=1;
i<
=n;
i++)
set(i);
for(j=i+1;
j<
j++)
{
p[++k].st=i;
p[k].ed=j;
p[k].dis=a[i][j];
//先把所有城市之间的路段看成一个边
}
sort(p+1,p+k+1,cmp);
//把所有的边按从小到大进行排序
intcount=0;
=k;
if(find(p[i].st)!
=find(p[i].ed))//如果这两点连接在一起不构成一个回路,则执行下面操作
第%d条路段为:
%d--%d,权值为%d\n"
++count,p[i].st,p[i].ed,p[i].dis);
//将这条边的起点、终点打印出来
ans+=p[i].dis;
//说明这条路段要用
Union(p[i].st,p[i].ed);
遍历所有城市的最短路程为:
%d\n"
ans);
//最短遍历的路程
//printf("
________________________________\n"
//普里姆算法
intprim()
intclose[100],low[100],i,j,ans=0;
//close[j]表示离j最近的顶点,low[j]表示离j最短的距离
booluse[100];
use[1]=1;
for(i=2;
low[i]=a[1][i];
//初始化
close[i]=1;
use[i]=0;
n;
intmin=100000000,k=0;
for(j=2;
if(use[j]==0&
&
min>
low[j])//找到最小的low[]值,并记录
min=low[j];
k=j;
//printf("
%d%d\n"
close[k],k);
if(use[j]==0&
low[j]>
a[k][j])
low[j]=a[k][j];
//修改low[]值和close[]值
close[j]=k;
ans+=a[close[k]][k];
returnans;
//求最短路径-单源点到其余点的最短路径(Dijkstra算法)
voidShortestPath_DIJ(intx,inty)//X指单源点,y指目标点
inti,d[100],j;
use[i]=0;
d[i]=a[x][i];
use[x]=1;
//这个点肯定用过
d[x]=0;
i++)//执行n-1次操作
intmin=100000000,v;
for(j=1;
d[j])//找出最短距离的
min=d[j];
v=j;
use[v]=1;
d[j]>
min+a[v][j])//修改d[]的值
d[j]=min+a[v][j];
%d城市到城市%d的最短距离为:
x,y,d[y]);
//求每一对顶点之间的最短路径(Floyd算法)
intb[100][100];
voidShortestPath_FLOYD()//这个算法耗时多(n^3),不过容易理解
inti,j,k;
b[i][j]=a[i][j];
//先b[][]进行保存,避免a[][]的值发生变化
for(k=1;
k<
k++)
if(b[i][j]>
b[i][k]+b[k][j])
b[i][j]=b[i][k]+b[k][j];
while
(1)
intst,ed;
请输入两个城市的编号:
\n"
//对此进行多次操作
%d%d"
st,&
ed);
%d城市到%d城市的最短距离为:
st,ed,b[st][ed]);
charstr[100];
是否要继续?
yesorno\n"
%s"
str);
if(strcmp(str,"
no"
)==0)
{//printf("
break;
voidshuru()//输入城市信息
inti,j;
if(n!
=0)
是否要确定输入新的城市之间的信息?
yesorno?
return;
请输入城市的个数:
n);
输入%d个城市的邻接矩阵:
n);
a[i][j]);
voidchaxun()//一个查徇两个城市最短径的操作
intt1,t2;
输入第一个城市的编号:
t1);
输入第二个城市的编号:
t2);
ShortestPath_DIJ(t1,t2);
//调用
if(n==0)
这里没有城市之间的信息\n"
return;
xin_input();
请选择以上功能:
1-3\n"
intm1;
m1);
if(m1==1)
Kruskal();
elseif(m1==2)
chaxun();
//else
//break;
intans;
ans=prim();
if(ans>
=100000000)
不能构成并查集\n"
\n\n\n\n能构成并查集!
\n\n\n\n\n"
intmain()
switch(menu())
case1:
shuru();
case2:
judge();
case3:
chaxun_func();
case4:
gotoloop;
loop:
;
return0;