一.需求分析1.运行环境硬件:计算机486/64M以上操作系统: WIN9x 以上/WIN2000/WIN XP/WIN ME相关软件:vistualC++2.程序所实现的功能:(1)建立并显示图的邻接表。
(2)深度优先遍历,显示遍历结果。
(3)对该图进行拓扑排序,显示排序结果。
(4)给出某一确定顶点到所有其它顶点的最短路径。
3.程序的输入,包含输入的数据格式和说明(1)输入顶点数,及各顶点信息(数据格式为整形)(2)输入边数,及权值(数据格式为整形)4.程序的输出,程序输出的形式(1)输出图的邻接表、深度优先遍历结果、拓扑排序结果。
(2)输入某一确定顶点到其它所有顶点的最短路径。
5.测试数据二、设计说明1、算法设计的思想建立图类,建立相关成员函数。
最后在主函数中实现。
具体成员函数的实现请参看源程序。
2、主要的数据结构设计说明图邻接矩阵、邻接表的建立。
图的深度优先遍历、拓扑排序、顶点之间的最短路径。
3、程序的主要模板template <class Type> class Graph4、程序的主要函数Graph、link()、DFTraverse()、TopologicalOrder()、TopologicalOrder()、GetVertexPos()、ShortestPath三、上机结果及体会1、实际完成的情况说明主要程序参考教材《数据结构——C++版》。
2、程序的性能分析可连续建图3、上机过程中出现的问题及其解决方案。
编译没有错误,但结果有问题。
解决方案:虽然程序的编译通过,只能说明语法上没有问题,结果只所以不正确是因为算法上原因。
4、程序中可以改进的地方说明程序中的深度优先遍历,浪费空间较大,可以考虑用循环来做。
但这样将付出代码长度度加长的代价。
5、程序中可以扩充的功能及设计实现假想实现假想:随用户的输入可以随时动态的显示图的生成。
6、收获及体会编写程序即是一件艰苦的工作,又是一件愉快的事情。
最大的收获:编程时如果遇到看似简单但又无法解决的问题,很容易灰心丧气。
此时切不可烦躁,一定要冷静的思考,认真的分析。
要勇敢的面对问题,勇敢的接受问题,勇敢的处理问题,最后最勇敢的解决问题。
四、参考文献数据结构(C++版)叶核亚主编机械工业出版社数据结构经典算法实现与习题解答汪杰编著人民邮电出版社数据结构课程设计苏仕华编著机械工业出版社数据结构程序设计题典李春葆编著清华大学出版社数据结构课程与题解(用C/C++描述)胡圣荣编著北京大学出版社[程序运行流程图]char op //程序控制变量If(op=='Y'||op=='y') if(op=='N'||op=='n')//本程序是邻接矩阵,邻接表的利用,共有4项功能,分别是://(1)建立并显示图的邻接表。
//(2)以非递归方式进行深度优先遍历,显示遍历结果。
//(3)对该图进行拓扑排序,显示排序结果。
//(4)给出某一确定顶点到所有其它顶点的最短路径。
#include<iostream>using namespace std;const int MaxVertexes=20; //最大的顶点数const int b=10000;template <class Type> class Graph ;struct ArcNode{//定义边结点friend class Graph <class Type>;int adjvex; //和边(或弧)相关联的另一个顶点序号int weight; //边(或弧)上的信息ArcNode *nextarc ; //指向下一条边结点的指针ArcNode(int v,int w ) : adjvex( v ),weight(w),nextarc( NULL ){ }};//构造函数template <class Type>struct VertexNode{// 定义顶点结点friend class Graph <class Type>;Type data; //顶点的信息ArcNode *firstarc ; //指向依附该顶点的边链表};template <class Type>class Graph{VertexNode<Type> * VTable; //顶点表int CurrentNumVertexes; //当前的顶点数int CurrentNumArcs; //当前的边(或弧)数public:int GetVertexPos( const Type &v );// 取顶点v在数组中的位置Graph(Type v[],int num=MaxVertexes); //构造函数Type GetValue(int v); //取图中顶点v的值,如果顶点v不存在则返回空 int Getweight(int v1,int v2); //取边(或弧)上的权值int GetFirstNeighbor(int v); //取图中顶点v的第一个邻接点的序号。
如果不存在返回-1int GetNextNeighbor(int v1, int v2); //取图中下一个邻接点int Arcs[MaxVertexes][MaxVertexes];//用数组记录每个边的信息int InVertex(Type &v); //在图中插入结点int InsertArc(int v1, int v2,int w);//在图中插入依附于v1和v2的边或弧,w是信息int NumberOfVertexes( ){return CurrentNumVertexes; } //返回当前的顶点数int NumberOfArcs(){ return CurrentNumArcs; } //返回当前的边(或弧)数int *dist; //最短路径长度数组int *InDegree; //入度数组,记录每个顶点的入度int *path; //最短路径的数组int *s; //最短路径终点数组void link(); //输出邻接链表void DFS(const int v,int visited[]);//深度优先搜索void DFTraverse (); //深度遍历void TopologicalOrder(); //拓扑排序void ShortestPath(int n,int v);//最短路径};//////////////////////////////////////////////////////////////////////////////// ///template<class Type>int Graph<Type>::GetVertexPos(const Type &v ){ //根据顶点v查找该顶点在邻接表中的位置for(int i=0;i<CurrentNumVertexes;i++)if(VTable[i].data==v) return i;return -1;}template<class Type>Graph<Type>::Graph( Type v[] , int num=MaxVertexes) : CurrentNumVertexes(0), CurrentNumArcs(0){Type tail, head;int i=0,e,h,t,w,p=0;while(p<MaxVertexes){for(int j=0;j<MaxVertexes;j++){Arcs[p][j]=b;if(p==j) {Arcs[p][j]=0;}}p++;}InDegree=new int[MaxVertexes];VTable=new VertexNode<Type>[MaxVertexes];//创建顶点表for(i=0;i<num;i++) //输入各顶点信息{ InVertex(v[i]); //在顶点表中插入顶点v[i]InDegree[i]=0;}cout<<"输入边的条数:"; cin >> e;//输入边的条数cout<<endl;for(i=0;i< e;i++){ //逐条输入边cout<<"输入第"<<i+1<<"条边:(弧头,弧尾,权值)";cin>>tail>>head>>w; //输入一条边int j=GetVertexPos(head);while((t=GetVertexPos(tail))==-1)cout<<"输入的顶点(tail)不存在";while((h = GetVertexPos(head ))==-1)cout<<"输入的顶点(head)不存在";InsertArc (t,h,w); //插入一条边InDegree[j]++; //顶点j的入度加1cout<<endl;}}template<class Type>Type Graph<Type>::GetValue(int v){ //取图中顶点v的值,如果顶点v不存在,则返回空 if(v>=0&&v<CurrentNumVertexes) return VTable[v].data;return NULL;}template<class Type>int Graph<Type>::Getweight(int v1,int v2){//取出以顶点v1和v2为两端点的边上的权值if(v1>=0&&v1<CurrentNumVertexes&&v2>=0&&v2<CurrentNumVertexes){ArcNode *p=VTable[v1].firstarc;while(p!=NULL){if(p->adjvex==v2) {return p->weight;}else {p=p->nextarc; }}} return NULL;}template<class Type>int Graph<Type>::GetFirstNeighbor(int v){//查找顶点v的第一个邻接顶点的位置if(v>=0&&v<CurrentNumVertexes){ArcNode *p=VTable[v].firstarc;if(p!=NULL) return p->adjvex;}return -1;}template<class Type>int Graph<Type>::GetNextNeighbor(int v1,int v2){//查找顶点v1的在v2之后的下一个邻接顶点,如果不存在返回-1if (v1!=-1){ArcNode *p=VTable[v1].firstarc;while(p!=NULL){if(p->adjvex==v2&&p->nextarc!=NULL)return p->nextarc->adjvex;//返回下一个邻接顶点在邻接表中的位置else p=p->nextarc;}}return -1;//没有查到下一个邻接顶点返回-1}template<class Type>int Graph<Type>::InsertArc(int v1,int v2,int w){//在图中插入弧<v1,v2>if(v1>=0&&v1<CurrentNumVertexes){Arcs[v1][v2]=w;ArcNode *newnode =new ArcNode(v2,w);ArcNode *h=VTable[v1].firstarc;if(h!=NULL){ArcNode *p=h;while(h!=NULL&&h->adjvex<v2){p=h; h=h->nextarc;}newnode->nextarc=p->nextarc;p->nextarc=newnode;return 1;}VTable[v1].firstarc=newnode;return 1;}return -1;}template<class Type>int Graph<Type>::InVertex(Type &v){//在图中插入顶点,插入成功则返回1,否则返回0if(CurrentNumVertexes<MaxVertexes-1){//若顶点表未满VTable[CurrentNumVertexes].data=v;VTable[CurrentNumVertexes].firstarc=NULL;CurrentNumVertexes++; return 1;}return -1;}/////////////////////////////////////////////////////////////////////// //以下是实验要求的函数//输出邻接表template<class Type>void Graph<Type>::link(){cout<<"输出邻接表:"<<endl;for(int i=0;i<CurrentNumVertexes;i++){cout<<GetValue(i);int a=GetFirstNeighbor(i);if(a!=-1) cout<<"->"<<GetValue(a)<<Getweight(i,a);for(int j=a;j!=-1;j=a){a=GetNextNeighbor(i,j);if(a!=-1) cout<<"->"<<GetValue(a)<<Getweight(i,a);}cout<<endl;}}//拓扑排序template<class type>void Graph<type>::TopologicalOrder(){int m=0;//m为输出的顶点数,初始值为0for(int i=0;i<CurrentNumVertexes;i++){for(int n=0;n<CurrentNumVertexes;n++){if(InDegree[n]==0){m++;//输出的顶点数加1cout<<VTable[n].data<<endl;InDegree[n]=-1;for(int t=0;t<CurrentNumVertexes;t++){if(n>=0&&n<CurrentNumVertexes){if(t>=0&&t<CurrentNumVertexes){if(Arcs[n][t]!=0&&Arcs[n][t]!=b)InDegree[t]--;}}}for(int h=0;h<CurrentNumVertexes;h++){cout<<InDegree[h]<<" ";} cout<<endl; break;}}}if(m<CurrentNumVertexes) cout<<"AOV网络中有回路(有向环)!"<<endl; }//深度遍历template<class Type>void Graph<Type>::DFS(const int v,int visited[ ]){cout<< VTable[v].data<<" "; //访问顶点 vvisited[v] =1; //顶点v 作访问标记int w = GetFirstNeighbor (v);while (w != -1) { //若顶点 w 存在if (!visited[w]) DFS (w,visited);w = GetNextNeighbor(v,w);} //重复检测 v 的所有邻接顶点}template<class Type>void Graph <Type> ::DFTraverse (){int i, n = NumberOfVertexes() ; //取图的顶点个数int * visited = new int [n]; //定义访问标记数组 visitedfor ( i = 0; i < n; i++ )visited [i] = 0; //访问标记数组 visited 初始化for ( i = 0; i < n; i++ ) //对图中的每一个顶点进行判断if (!visited [i]) DFS (i, visited );delete[ ]visited; //释放 visited}//求最短路径template<class Type>void Graph<Type>::ShortestPath(int n,int v){int min,u;dist=new int[n]; s=new int[n]; path=new int[n];for(int j=0;j<n;j++){dist[j]=Arcs[v][j]; s[j]=0;if(j!=v&&dist[j]<MaxVertexes) path[j]=v;else path[j]=-1; s[v]=1;}for(int i=0;i<=n-1;i++){min=MaxVertexes; u=v;for(int j=0;j<n;j++)if(!s[j]&&dist[j]<min){u=j; min=dist[j];}s[u]=1;for(int w=0;w<n;w++)if(!s[w]&&dist[u]+Arcs[u][w]<dist[w]){dist[w]=dist[u]+Arcs[u][w];path[w]=u;}if(v!=i&&dist[i]!=10000&&v!=path[i])cout<<GetValue(v)<<"到顶点"<<GetValue(i)<<"的最短路径是:"<<GetValue(v)<<GetValue(path[i])<<GetValue(i)<<endl;else if(v!=i&&dist[i]!=10000)cout<<GetValue(v)<<"到顶点"<<GetValue(i)<<"的最短路径是:"<<GetValue(path[i])<<GetValue(i)<<endl;}for(int m=0;m<n;m++)cout<<GetValue(v)<<"到顶点"<<GetValue(m)<<"的最短路径长度是:"<<dist[m]<<endl;}//主函数void main(){char op;do{int m,i=0,j=0,w;char a[20],c;cout<<"请你输入顶点的个数:"; cin>>m;for(i=0;i<m;i++){cout<<"请输入第"<<j<<"个结点:";cin>>a[i]; cout<<endl; j=j+1;}Graph<char>G(a,m);G.link();cout<<"深度遍历:"<<endl;G.DFTraverse();cout<<endl;cout<<"拓扑排序:"<<endl;G.TopologicalOrder();cout<<endl;cout<<"输入最小路径的源头结点:"<<endl;cin>>c;w=G.GetVertexPos(c);G.ShortestPath(m,w);loop:cout<<"是继续?(Y or N)"<<endl;cin>>op;if(op=='N'||op=='n')break;if(op!='Y'&&op!='y'&&op!='N'&&op!='n')goto loop; }while(op=='Y'||op=='y');}。