大数据结构上机报告材料4图.docx
- 文档编号:30060232
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:24
- 大小:178.89KB
大数据结构上机报告材料4图.docx
《大数据结构上机报告材料4图.docx》由会员分享,可在线阅读,更多相关《大数据结构上机报告材料4图.docx(24页珍藏版)》请在冰豆网上搜索。
大数据结构上机报告材料4图
数据结构上机4
实现最短路径(单源、每对顶点)和最小生成树(Prim)算法。
2015、5、23
1、需求分析
构造一个图,实现单源最短路径和每对顶点之间的最短路径,并且实现最小生成树,将结果显示在屏幕上输出。
输入数据类型:
构造图的数据是整型数字。
程序功能:
输入或者从文件读取构造图的参数,进行构图,并计算出单源最短路径和每个顶点最短路径,实现最小生成树。
测试数据:
正确输入:
错误输入:
2、概要设计
图ADT的定义:
classGraph{
public:
intnumVertex;
intnumEdge;
int*Mark;
int*Indegree;
Graph(intnumVert){//有参构造函数,动态创建标记和度的数组,初始化边数、度数和访问
numVertex=numVert;
numEdge=0;
Indegree=newint[numVertex];
Mark=newint[numVertex];
for(inti=0;i Mark[i]=UNVISITED; Indegree[i]=0; } } ~Graph(){//析构函数,删除数组 delete[]Mark; delete[]Indegree; } intVerticesNum(){//返回顶点个数 returnnumVertex; } boolIsEdge(Edgeed){//判断是否是图的边 if(ed.weight>0&&ed.weight returntrue; returnfalse; } virtualEdgeFirstEdge(intoneVertex)=0;//返回与顶点oneVertex相关联的第一条边 virtualEdgeNextEdge(EdgepreEdge)=0;//返回与边PreEdge有相同关联顶点oneVertex的下一条边 intEdgesNum()//返回图的边数 { returnnumEdge; } intFromVertex(EdgeoneEdge)//返回边oneEdge的始点 { returnoneEdge.from; } intToVertex(EdgeoneEdge)//返回边oneEdge的终点 { returnoneEdge.to; } intWeight(EdgeoneEdge)//返回边oneEdge的权 { returnoneEdge.weight; } virtualvoidsetEdge(intfrom,intto,intweight)=0;//虚函数,设置边的起点终点以及权值,在子类实例化 virtualvoiddelEdge(intfrom,intto)=0; }; 主程序流程: 错误输入 正确输入 错误选项 正确选项 3、详细设计 1、实现ADT的数据类型: 整型数字; 2、算法描述: 单源最短: 初始集合S只包含源点s,即S={s}。 设v是V中某顶点,把从s到v且中间只经过集合S中顶点的路径称“从源到v的特殊路径”,用一维数组D记录当前找到的从s到每个顶点的最短特殊路径长度。 D初始,若s到v有弧,D[v]存弧的权值,否则存∞。 取最小,每次从集合V-S中取出一个最短特殊路径长度最小的顶点u,将u加入集合S,修改权值(修改D中未求出的最短路径长度): 由于引入u,对未求出最短路径的顶点i进行判断,若满足: D[i]>D[u]+W[u,i]则改为最短,令D[i]=D[u]+W[u,i]另设立存储最短路径中当前顶点前驱顶点域pre,用于存顶点u。 每对顶点最短路径算法: 递归地产生一个矩阵序列adj(0),adj (1),…,adj(k),…,adj(n) adj(k)[i,j]等于从顶点Vi到顶点Vj中间顶点序号不大于k的最短路径长度。 假设已求得矩阵adj(k-1),那么从顶点Vi到顶点Vj中间顶点的序号不大于k的最短路径有两种情况: 一种是中间不经过顶点Vk,那么就有adj(k)[i,j]=adj(k-1)[i,j] 另一种是中间经过顶点Vk,那么adj(k)[i,j] Prim最小生成树算法: 从图中任意一个顶点开始,首先把这个顶点包括在MST里,然后在那些其一个端点已在MST里,另一个端点还未在MST里的边中,找权最小的一条边,并把这条边和其不在MST里的那个端点包括进MST里。 如此进行下去,每次往MST里加一个顶点和一条权最小的边,直到把所有的顶点都包括进MST里。 4、调试分析 在实现每个顶点最短路径和最小生成树的过程中出现好多次错误,最后是借鉴参考了好多类似程序才完成。 5、使用说明 界面有提示会如何输入数据,选择相应的选项就会按步骤构建出图。 6、测试结果 手动输入数据进行构图: 选择保存的文件进行构图: 7、源程序 #include #include #include #include #defineUNVISITED0 #defineVISITED1 #defineINFINITY9999999 #defineROOT-1 usingnamespacestd; classEdge{ public: intfrom,to,weight; Edge(){ from=-1;to=-1;weight=0; } Edge(intf,intt,intw){ from=f;to=t;weight=w; } }; classGraph{ public: intnumVertex; intnumEdge; int*Mark; int*Indegree; Graph(intnumVert){//有参构造函数,动态创建标记和度的数组,初始化边数、度数和访问 numVertex=numVert; numEdge=0; Indegree=newint[numVertex]; Mark=newint[numVertex]; for(inti=0;i Mark[i]=UNVISITED; Indegree[i]=0; } } ~Graph(){//析构函数,删除数组 delete[]Mark; delete[]Indegree; } intVerticesNum(){//返回顶点个数 returnnumVertex; } boolIsEdge(Edgeed){//判断是否是图的边 if(ed.weight>0&&ed.weight returntrue; returnfalse; } virtualEdgeFirstEdge(intoneVertex)=0;//返回与顶点oneVertex相关联的第一条边 virtualEdgeNextEdge(EdgepreEdge)=0;//返回与边PreEdge有相同关联顶点oneVertex的下一条边 intEdgesNum()//返回图的边数 { returnnumEdge; } intFromVertex(EdgeoneEdge)//返回边oneEdge的始点 { returnoneEdge.from; } intToVertex(EdgeoneEdge)//返回边oneEdge的终点 { returnoneEdge.to; } intWeight(EdgeoneEdge)//返回边oneEdge的权 { returnoneEdge.weight; } virtualvoidsetEdge(intfrom,intto,intweight)=0;//虚函数,设置边的起点终点以及权值,在子类实例化 virtualvoiddelEdge(intfrom,intto)=0; }; template classLink { public: Elemelement;//表目的数据 Link*next;//表目指针,指向下一个表目 Link(constElem&elemval,Link*nextval=NULL)//构造函数 { element=elemval;next=nextval; } Link(Link*nextval=NULL)//构造函数 { next=nextval; } }; //链表 template classLList { public: Link LList()//构造函数 { head=newLink } voidremoveall()//释放边表所有表目占据的空间 { Link while(head! =NULL)//逐步释放每个表目占据的空间 { fence=head; head=head->next; deletefence; } } ~LList(){removeall();}//析构函数 }; structlistUnit//邻接表表目中数据部分的结构定义 { intvertex;//边的终点 intweight;//边的权 }; classGraphl: publicGraph { friendclassGraphdup;//Graphdup是下面我们将讨论的邻接多重表的实现方式 private: LList public: Graphl(intnumVert): Graph(numVert)//构造函数 { graList=newLList } ~Graphl()//析构函数 { delete[]graList;//释放空间 } EdgeFirstEdge(intoneVertex)//返回顶点oneVertex的第一条边 { EdgemyEdge;//边myEdge将作为函数的返回值 myEdge.from=oneVertex;//将顶点oneVertex作为边myEdge的始点 Link if(temp->next! =NULL)//如果顶点oneVertex的第一条边确实存在 { myEdge.to=temp->next->element.vertex; myEdge.weight=temp->next->element.weight; } returnmyEdge;//如果找到了顶点oneVertex的第一条边,则返回的myEdge确实是一条边;如果没有找到顶点oneVertex的第一条边,则myEdge的成员变量to为-1,根据IsEdge函数判断可知myEdge不是一条边 } EdgeNextEdge(EdgepreEdge)//返回与边PreEdge有相同关联顶点oneVertex的下一条边 { EdgemyEdge;//边myEdge将作为函数的返回值 myEdge.from=preEdge.from;//将边myEdge的始点置为与上一条边preEdge的始点相同 Link while(temp->next! =NULL&&temp->next->element.vertex<=preEdge.to)//确定边preEdge在边表中的位置,如果边preEdge的下一条边确实存在,则temp->next指针指向下一条边的表目 temp=temp->next; if(temp->next! =NULL)//边preEdge的下一条边存在 { myEdge.to=temp->next->element.vertex; myEdge.weight=temp->next->element.weight; } returnmyEdge; } voidsetEdge(intfrom,intto,intweight)//为图设定一条边 { Link while(temp->next! =NULL&&temp->next->element.vertex temp=temp->next; if(temp->next==NULL)//边(from,to)或 { temp->next=newLink temp->next->element.vertex=to; temp->next->element.weight=weight; numEdge++; Indegree[to]++; return; } if(temp->next->element.vertex==to)//边(from,to)或 { temp->next->element.weight=weight; return; } if(temp->next->element.vertex>to)//边(from,to)或 { Link temp->next=newLink temp->next->element.vertex=to; temp->next->element.weight=weight; temp->next->next=other; numEdge++; Indegree[to]++; } } voiddelEdge(intfrom,intto)//删掉图的一条边 { Link while(temp->next! =NULL&&temp->next->element.vertex temp=temp->next; if(temp->next==NULL)return;//边(from,to)或 if(temp->next->element.vertex==to)//边(from,to)或 { Link deletetemp->next; temp->next=other; numEdge--; Indegree[to]--; } } }; voidDFS(Graph&G,intV)//图的深度优先周游 { G.Mark[V]=VISITED;//标记该点 cout< for(Edgee=G.FirstEdge(V);G.IsEdge(e);e=G.NextEdge(e))//由该点所连的边进行深度优先周游 { if(G.Mark[G.ToVertex(e)]==UNVISITED)//访问V邻接到的未被访问过的顶点,并递归地按照深度优先的方式进行周游 DFS(G,G.ToVertex(e)); } } voidBFS(Graph&G,intV)//广度优先周游 { usingstd: : queue; queue G.Mark[V]=VISITED;//访问顶点V,并标记其标志位 cout< Q.push(V);//V入队 while(! Q.empty())//如果队列仍然有元素 { intV=Q.front();//顶部元素 Q.pop();//出队 for(Edgee=G.FirstEdge(V);G.IsEdge(e);e=G.NextEdge(e))//将与该点相邻的每一个未访问点都入队 { if(G.Mark[G.ToVertex(e)]==UNVISITED)//访问V邻接到的所有未被访问过的顶点 { G.Mark[G.ToVertex(e)]=VISITED;//访问顶点V,并标记其标志位 cout< Q.push(G.ToVertex(e));//入队 } } } } voidgraph_traverse(Graph&G,intfs)//选择周游方式 { for(inti=0;i G.Mark[i]=UNVISITED; for(i=0;i { if(G.Mark[i]==UNVISITED) { if(fs==1) DFS(G,i);//深度优先搜索 if(fs==2) BFS(G,i);//广度优先搜索 } } cout< } voidmain(){ intchoice,choice1,choice2; intisDirected;//标记是否有向图 intnumVertex;//图的顶点个数(边数将在setEdge中被自动修改) intfrom,to,weight;//读入每条边的起点,终点和权 charfilename[20]; ifstreamGraphSou;//输入文件流 stringstr; cout<<"请选择: "< cout<<"1: 输入构图的参数进行图的构造! "< cout<<"2: 选择已经存好的文件进行图的构造! "< cout<<"输入其它数字则无效"< cin>>choice; if(choice! =1&&choice! =2){ cout<<"输入有误! "< exit(0); } if(choice==1){ cout<<"********************************************************************"< cout<<"0表示构造图为无向图,若是1则为有向图"< cout<<"6表示构造图的顶点个数"< cout<<"0112依次表示为图的起点、终点以及权值"< cout<<"1221"< cout<<"......"< cout<<"********************************************************************"< cout<<"按以上格式输入构图的参数,并以#结束: "< getline(cin,str,'#'); cout<<"请输入想要保存图的文件名: "< cin>>filename;//获取文件名 ofstreamGraphSave(filename,ios: : trunc); GraphSave< GraphSave.close(); } if(choice==2){ cout<<"请选择文件: "< cout<<"1: a.txt"< cout<<"2: b.txt"< cout<<"3: c.txt"<<
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 上机 报告 材料