数据结构设计无向图.docx
《数据结构设计无向图.docx》由会员分享,可在线阅读,更多相关《数据结构设计无向图.docx(17页珍藏版)》请在冰豆网上搜索。
数据结构设计无向图
数据结构课程设计
――无向图
学校专业班级姓名学号任课教师
题目3:
以邻接链表的方式确定一个无向网,完成:
⑴建立并显示出它的邻接矩阵;
⑵对该图进行广度优先遍历,显示遍历的结果,(并随时显示队列的
入、出情况);
⑶普里姆算法构造其最小生成树,随时显示其构造的过程;
⑷用克鲁斯卡尔算法构造其最小生成树,随时显示其构造的过程。
一、需求分析
1.运行环境:
MicrosoftVisualStudio2012
2.程序所实现的功能:
a)建立并显示图的邻接矩阵;
b)广度优先遍历该图,显示遍历结果;
c)用普里姆算法构造该图的最小生成树,显示构造过程;
d)用克鲁斯卡尔算法构造该图的最小生成树,显示构造过程。
3.程序的输入,包含输入的数据格式和说明:
a)输入顶点数,及各顶点信息(数据格式为整形);
b)输入弧以及其权值(数据格式为整形)。
1.程序的输出,程序输出的形式:
a)输出图的邻接矩阵;
b)广度优先遍历结果;
c)普里姆算法构造最小生成树的结果;
d)克鲁斯卡尔算法构造最小生成树的结果
2.测试数据,如果输入的数据量较大,需要给出测试数据:
a)顶点个数:
5
b)各个顶点为:
ABCDE
c)输入所有的弧(格式为“顶点顶点权值”)为:
AB10AC4BD3CD5BE6DE9
二、设计说明
算法设计的思想:
建立图类,建立相关成员函数。
最后在主函数中实现。
具体成员函数的实现请参看源程序。
在本次的设计中,我采用的是多文件的编程方式。
每个类写成了一个头文件。
这样有助于阅读和查看源程序。
1.邻接链表:
邻接链表是一种链式存储结构。
在邻接链表中,对图中每个顶点建立一个单链表,第i个单链表中的结点表示依附于顶点Vi的边(对有向图是以顶点Vi为尾的弧)。
每个结点由3个域组成,其中邻接点域指示与顶点Vi邻接的点在图中的位置,链域指示下一条边或弧的结点;数据域存储和边或弧相关的信息,如权值等。
所以一开始必须先定义邻接链表的边结点类型以及邻接链表类型,并对邻接链表进行初始化,然后根据所输入的相关信息,包括图的顶点数、边数、是否为有向,以及各条边的起点与终点序号,建立图的邻接链表。
2.邻接矩阵:
图的邻接矩阵存储表示即是数组存储表示,在邻接矩阵中,我们定义两个数组分别存储数据元素的信息和数据元素之间的关系(边或弧)的信息,以二维数组表示有n个顶点的图时,需存放n个顶点信息和n的平方个弧信息的存储量。
借助于邻接矩阵容易判定任意两个顶点之间是否有边或弧相连,并容易求得各个顶点的度。
故在建立邻接矩阵之前,必须先定义顶点关系类型和相关指针指示弧的信息。
3.广度优先遍历:
假设从图总某顶点出发,在访问了v之后依次访问v的各个未曾访问到的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的邻接点”先于“后被访问的邻接点”被访问,直至图中所有已被访问的邻接点都被访问到。
若此时图中尚有顶点未被访问到,则另选图中一个未曾被访问的顶点作为起始点,重复上述过程,直至图中所有顶点都被访问到为止。
换句话说,广度优先搜索遍历图的过程是以v为起始点,由近及远,依次访问饿v有路径相通且路径长度为1,2…•的顶点。
和深度优先搜索类似,在遍历过程中也需要一个访问标志数组。
并且,为了顺次访问路径长度为2,3…的顶点,需
附设队列以存储已被访问的路径长度为1,2….的顶点。
所以要实现算法必须先建立一个元素类型为整形的空队列,并定义队首与队尾指针,同时也要定义一个标志数组以标记结点是否被访问。
同样,也是从初始点出发开始访问,访问初始点,标志其已被访问,并将其入队。
当队列非空时进行循环处理。
当结点被访问时对其
进行标志,并入队列。
通过while()循环,并以是否被访问为控制条件,访问所有结点,完成图的广度优先遍历。
4.普里姆算法:
假设N=(V,{E})是连通网,TE是N上最小生成数中边的集合。
算法从U={UO},TE={}开始,重复执行如下操作;在所有的边(u,v)中找一条代价最小的边(uO,vO)并入集合TE,同时V0并入U,直到U=V为止。
此时TE中必有n-1条边,贝y,T=(V,{TE})为N的最小生成树。
5.克鲁斯卡尔算法:
假设连通网N=(V,{E}),则令最小生成树的初始状态为只有n个顶点且无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。
在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,贝将此边加入到T中,否贝舍去此边而选择下一条代价最小的边。
依次类推,直到T中的所有顶点都在同一个连通分量上为止。
主要的数据结构设计说明:
图的邻接矩阵、邻接表的建立。
图的广度优先遍历以及分别用普里姆算法和克鲁斯卡尔算法构造最小生成树
程序的主要流程图:
无向网
程序的主要模块,要求对主要流程图中出现的模块进行说明:
用邻接链表的方式确定一个无向图,以邻接矩阵的方式输出,再进行图的广度优先遍历以及分别用普里姆算法和克鲁斯卡尔算法构造最小生成树并输出。
程序的主要函数说明:
intlocatepoint(string);定位节点位置
voidBreadth_traversal()广度优先遍历
voidprintgragh();邻接矩阵的输出
voidprim();普里姆算法
voidktus();克鲁斯卡尔算法
三、上机结果及体会
1.上机过程中出现的问题及其解决方案。
问题:
刚开始编译没有错误,但结果有问题。
在其中的普里姆算
法和克鲁斯卡尔算法的循环过程中,对循环控制变量设置不当,导致
程序陷入死循环之中。
解决方案:
调整改变循环控制变量。
2.程序中可以改进的地方说明
程序中的广度优先遍历,可以考虑用循环来做,也可以用栈
来实现。
在本程序中,两个没有联系的顶点之间的权值的无穷大我是
用“0”来表示的。
可以考虑用一个特殊字符来实现。
四、实验源程序
头文件
*******************************************************************************
node_linklist.h#ifndefNODE_LINKLIST
#defineNODE_LINKLISTclassnode_array;
//邻接链表链结点
classnode_linklist
{
public:
imposition;
intweight;
node_linklist*next;
node_linklist(inta,intb){position=a;weight=b;next=NULL;}node_linklist(){position=NULL;weight=NULL;next=NULL;}~node_linklist(){}
};
#endif
*******************************************************************************
node_array.h#ifndefNODE_ARRAY
#defineNODE_ARRAY
//邻接链表数组结点
classnode_array
{
public:
node_linklist*next;
stringdata;
node_array(){data='\O';next=NULL;}
〜node_array(){}
};
#endif
*******************************************************************************
头文件
头文件
tu_matrix.h
#ifndefTU_MATRIX
#defineTU_MATRIX
//图类classtu_matrix
{
private:
intmatrix[MAX][MAX];
stringtoppoint[MAX];
intnumpoint;
node_arrayvertices[MAX];
public:
tu_matrix(){}
voidcreat();
intlocatepoint(string);//返回这个顶点的位置
voidBreadth_traversal();
voidprintgragh();
voidprim();
voidktus();
};
inttu_matrix:
:
locatepoint(stringb)
{
inti=0;
for(;i{
if(toppoint[i]==b)returni;
}
return-1;
}
voidtu_matrix:
:
creat()
{
stringdata,data1,data2;
intn,m,num;
//输入顶点个数
"<<'\t';
cout<<"请输入您要创建的无向图的顶点个数:
cin>>numpoint;
//输入顶点
cout<<"请依次输入该无向图的各个顶点:
"<for(inti=0;i{cin>>toppoint[i];
}
//以邻接链表确定无向网
node_linklist*(*end)=newnode_linklist*[numpoint];//指向数组链表的最后一个节点指针数组
int*pp=newint[numpoint];//辅助数组,当其中的值不为0时,表示该数组节点后面已经有至少一个链表节点,否则表示没有链表节点
for(inti=0;ipp[i]=0;
node_linklist*ppp=NULL;
coutvv"输入该无向图所有的弧,格式为:
顶点顶点权值”输入“000吉束"vvendl;
do
{
cin>>data1>>data2>>num;
n=locatepoint(data1);
m=locatepoint(data2);
if((n!
=-1)&&(m!
=-1))
{
if(!
pp[n])//如果该数组节点后面没有链表节点
{
ppp=newnode_linklist(m,num);
end[n]=vertices[n].next=ppp;
pp[n]=1;
}
else
{
end[n]->next=newnode_linklist(m,num);
end[n]=end[n]->next;
if(!
pp[m])//如果该数组节点后面没有链表节点{
ppp=newnode_linklist(n,num);
end[m]=vertices[m].next=ppp;
pp[m]=1;
}
else
{
end[m]->next=newnode_linklist(n,num);
end[m]=end[m]->next;
}
}
}while((data1!
="0")&&(data2!
="0")&&(num!
=0));
//根据邻接链表建立邻接矩阵
node_linklist*p;
for(inti=0;ifor(intj=0;jmatrix[i][j]=0;
for(inti=0;i{
p=vertices[i].next;
while(p)
{
n=p->position;
m=p->weight;
p=p->next;
matrix[i][n]=m;
};
}
deleteend;
voidtu_matrix:
:
printgragh()//打印无向网的邻接矩阵
{
cout<<"该图的邻接矩阵为:
"<<
"\n
inti,j;
for(i=0;i{
for(j=0;j{
cout<}
cout<}
cout<<"
}
voidtu_matrix:
:
Breadth_traversal()
{
int*flag=newint[numpoint];//记录顶点访问状态
int*queue=newint[numpoint+1];//记录未广度遍历的顶点数
intfront,rear;
front=rear=0;
inti;
cout<<"该图的广度优先遍历为:
"<<
"\n
"<"<"<
for(i=0;iflag[i]=0;//状态初始化
do
{
for(i=0;iif(flag[i]==0)
break;
if(i!
=numpoint)
{
cout<<">\t"<rear=(rear+1)%(numpoint+1);
queue[rear]=i;
cout<<"入队列\t"<flag[i]=1;
do
{
front=(front+1)%(numpoint+1);
cout<<"出队列\t"<for(intj=0;j{
if((matrix[queue[front]][j]!
=0)&&(flag[j]!
=1))
{
cout<<">\t"<rear=(rear+1)%(numpoint+1);
queue[rear]=j;
cout<<"入队列\t"<flag[j]=1;
}
}
}while(((rear+1)%(numpoint+1)!
=front)&&(rear!
=front));//队列结束条件,队列满或空
}
}while(i!
=numpoint);
cout<<""<}
voidtu_matrix:
:
prim()
{
intflag[MAX],point[MAX],n,m,x,p=0;//flag[]标志结点所属树,p表示已访问过的结点个数
intmatrixone[MAX][MAX];//辅助矩阵
for(inti=0;ifor(intj=0;jmatrixone[i][j]=matrix[i][j];
for(inti=0;iflag[i]=0;//标志位初始化
cout<<"用普里姆算法构造的最小生成树为:
"<<
"\n"<//先找到最小的一个弧
x=m=n=0;
for(inti=0;ifor(intj=i;j=0)
{
x=matrixone[i][j];
break;
}
if(x!
=0)
break;
}//预先给x一个没有被访问过的,且不是0的权值
for(inti=0;ifor(intj=i;j{
if((matrixone[i][j]!
=0)&&(matrixone[i][j]<=x))
{
x=matrixone[i][j];
m=i;n=j;
}
}
p+=2;
point[0]=m;point[1]=n;
flag[m]=flag[n]=1;
相连\t权值为\t"<cout<while(p{
x=m=n=0;
for(inti=0;i{
for(intj=i;jif(matrixone[i][j]!
=0&&((flag[i]==0&&flag[j]!
=0)||(flag[i]!
=0&&flag[j]==0)))
{x=matrixone[i][j];
break;
}
if(x!
=0)
break;
}//预先给x一个没有被访问过的,且不是0的权值
for(inti=0;i
{
for(intj=0;j{if((matrixone[j][point[i]]!
=0)&&matrixone[j][point[i]]<=x&&flag[j]==0)
{
x=matrixone[j][point[i]];
n=point[i];
m=j;
}
}
}
if(m!
=n&&x!
=0)
{
point[p]=m;
p++;
cout<flag[m]=1;
cout<<""<}voidtu_matrix:
:
ktus()
{
intflag[MAX],n,m,x,p,k;//flag[]标志结点所属树,p表示已访问弧个数
intmatrixtow[MAX][MAX];//辅助矩阵
for(inti=0;ifor(intj=0;jmatrixtow[i][j]=matrix[i][j];
cout<<"用克鲁斯卡尔算法构造的最小生成树为:
"<<
"\n"<for(inti=0;iflag[i]=0;//初始化
k=p=0;
while(p<(numpoint-1))
{
x=n=m=0;
for(inti=0;ifor(intj=i;jif(matrixtow[i][j]!
=0)
x=matrixtow[i][j];//预先给x一个没有被访问过的,且不是0的权值
for(inti=0;ifor(intj=0;jif((matrixtow[i][j]!
=0)&&(matrixtow[i][j]<=x))
{x=matrixtow[i][j];
m=i;n=j;
}
}
if(x!
=0&&m!
=n)
{
if(flag[n]!
=0)
if(flag[m]!
=0)
if(flag[n]==flag[m])//避免成环情况
{continue;}
else
{cout<p++;
flag[numpoint]=flag[m];
for(inth=0;hif(flag[h]==flag[numpoint])
flag[h]=flag[n];
}
else
{
cout<<else
if(flag[m]!
=O)
{
cout<}
else
{
coutvvtoppoint[n]vv"\t与顶点\t"<flag[n]=flag[m]=k;
p++;
}
matrixtow[m][n]=matrixtow[n][m]=0;
}
k++;
};
"vvendl;
源文件
coutvv"
}
#endif
*******************************************************************************
main.cpp
#includeviostream>
#includevstring>
#defineMAX40
usingnamespacestd;
#include"node_linklist.h"
#include"node_array.h"
#include"tu_matrix.h"
voidmain()
{
intk=1;
tu_matrix*graph;
while(k)
{
cout<<"===================================================================="<graph=newtu_matrix();
graph->creat();
graph->printgragh();
graph->Breadth_traversal();
graph->ktus();
graph->prim();
"<deletegraph;
cout<<"
ndl;
cout<<"\n如果您想继续建立另一个无向图,请输入,1?
;如果您想退出程序,请输入,0?
"<<"\n"<cin>>k;
}
system("pause");
五、输出结果显示
E:
\MyPnogr^m\Data5tnje\iS1i^计无口期。
出匹']宰程说计无冋関心e]
h"疋
—■
S£=:
=二二i===™=™===:
===—==.=—==:
=.=.==:
=—===—S=======M3=.====.==.==■=i=™=™=======砂成甫依—iflDCD
输入该无向图所有的弧,格球为:
“顶点顶点权值”-输入%0屮结束
AB5ftCtBD3BC6H9U
该團的邻崔矩阵为,
该图的广度优先遍历为;
巾囱囱RBGCJBDDCD一
■hJ、「IJ-卜列>5IJ5IJ>-一一或八一附一一入出一入一人出一人岀岀_
用克鲁浙卡邙哼注构造的爺小主成杯甘,
耳普亘鸦算法构喳的最寸住成甜为.
如果您担m续建立另一个兀向图’请输入;如果您想退岀程序,请输入"
六、收获及体会
在这次的上机实验中,我更深入地学习了图