图的遍历

来源:互联网 发布:w判断矩阵 编辑:程序博客网 时间:2024/05/16 16:20

题目 图的遍历

 

【问题描述】
1、掌握图的数据类型描述及特点。

2、对图分别采用邻接表和邻接矩阵表示,并进行深度遍历和广度遍历。

【实验内容】
       该程序开始时是通过用户输入的图的数据文件(.txt)所在的路径来读取对应文件中的图的数据,以此来构建,进而调用遍历算法函数来对图进行遍历,如果文件不存在或路径不正确,程序将会报告错误并终止;

本程序读取的文件的格式是.txt文件(大家也可以手工输入数据),其中存储的数据组成如下:

第一行:M  N M是图中结点的个数,N是图中弧的条数

第二行:DD10, 1表示该图是一个有向图,

0表示该图是一个无向图

第三行:M个互不相同的字符,代表每个结点的字符数据

接下来的N行,每行有2个字母P1P2,对于有向图,表示存在一条从P1P2的有向边;

对于无向图,表示在P1P2之间存在一条边;

程序中采用的图的存储结构为邻接表和邻接矩阵,对于有向图,一条弧将存储一个弧结点,对于无向图,一条弧将存储两条弧结点;



代码:

#include<iostream>#include<fstream>#include<queue>#include<stdlib.h>using namespace std;const int DefaultVertices=30;    //默认最大顶点数const int maxWeight=100;//代表无穷大template<class T,class E>struct Edge// 边的类定义{     int dest;//边的另一顶点位置     E cost;//权值  Edge<T,E> *link;//下一条边链指针  Edge(){}  Edge(int num,E weight):dest(num),cost(weight),link(NULL){}  bool operator != (Edge<T,E>& R)const//判边不等否  {   return (dest!=R.dest)?true:false;  }};template<class T,class E>struct Vertex//顶点类定义{     T data;//顶点  Edge<T,E> *adj;//头指针};template<class T,class E>class Graphlnk{  public:   Graphlnk(int sz=DefaultVertices);   ~Graphlnk();   T getValue(int i)//取顶点中值   {    return (i>=0&&i<numVertices)?NodeTable[i].data:0;   }   E getWeight(int v1,int v2);//返回权值   bool insertVertex(const T& vertex);//插入顶点   bool insertEdge(int v1,int v2,E cost);//插入无向边   bool insertEdge1(int v1,int v2,E weight);//插入有向边   int getFirstNeighbor(int v);//取第一个邻接顶点   int getNextNeighbor(int v,int w);//下一邻接顶点   void Build(Graphlnk<T,E>& G);//建立图   void Output(Graphlnk<T,E>& G);//输出图   void DFS(Graphlnk<T,E>& G,const T& v);//深度优先遍历   void BFS(Graphlnk<T,E>& G,const T& v);//广度优先遍历   void Readfile(Graphlnk<T,E>& G);   int NumberOfVertices(){return numVertices;}//返回当前顶点数   int NumberOfEdges(){return numEdges;}//返回当前边数  private:   int maxVertices;//图中最大顶点数   int numEdges;//当前边数   int numVertices;//当前顶点数   void DFS(Graphlnk<T,E>& G,int v,bool visited[]);   Vertex<T,E> *NodeTable;//顶点表   int getVertexPos(const T vertices)//给出顶点vertex在图中的位置   {    for(int i=0;i<numVertices;i++)     if(NodeTable[i].data==vertices)     return i;   return -1;   }};template<class T,class E>Graphlnk<T,E>::Graphlnk(int sz){//构造函数建立一个空邻接表       maxVertices=sz;    numVertices=0;    numEdges=0;       NodeTable=new Vertex<T,E>[maxVertices];//创建顶点表数组    if(NodeTable==NULL)    {        cerr<<"存储分配错!"<<endl;     exit(1);    }    for(int i=0;i<maxVertices;i++)     NodeTable[i].adj=NULL;};template<class T,class E>Graphlnk<T,E>::~Graphlnk(){       for(int i=0;i<numVertices;i++)//删除各边链表中的结点    {         Edge<T,E> *p=NodeTable[i].adj;   while(p!=NULL)   {       NodeTable[i].adj=p->link;    delete p;    p=NodeTable[i].adj;   }    }    delete []NodeTable;//删除顶点表数组};template<class T,class E>int Graphlnk<T,E>::getFirstNeighbor(int v){    if(v!=-1) {  Edge<T,E> *p=NodeTable[v].adj;     if(p!=NULL)   return p->dest; } return -1;};template<class T,class E>int Graphlnk<T,E>::getNextNeighbor(int v,int w){    if(v!=-1) {     Edge<T,E> *p=NodeTable[v].adj;     while(p!=NULL&&p->dest!=w)   p=p->link;  if(p!=NULL&&p->link!=NULL)   return p->link->dest; } return -1;};template<class T,class E>E Graphlnk<T,E>::getWeight(int v1,int v2){     if(v1!=-1&&v2!=-1)     {       Edge<T,E> *p=NodeTable[v1].adj;    while(p!=NULL&&p->dest!=v2)     p=p->link;    if(p!=NULL)     return p->cost;  }  return -1;};template<class T,class E>bool Graphlnk<T,E>::insertVertex(const T& vertex){    if(numVertices==maxVertices)  return false; NodeTable[numVertices].data=vertex; numVertices++; return true;};template<class T,class E>bool Graphlnk<T,E>::insertEdge(int v1,int v2,E weight)//插入无向边{     if(v1>=0&&v1<numVertices&&v2>=0&&v2<numVertices)  {      Edge<T,E> *q,*p=NodeTable[v1].adj;   while(p!=NULL&&p->dest!=v2)    p=p->link;   if(p!=NULL)    return false;   p=new Edge<T,E>;   q=new Edge<T,E>;   p->dest=v2;   p->cost=weight;   p->link=NodeTable[v1].adj;   NodeTable[v1].adj=p;   q->dest=v1;   q->cost=weight;   q->link=NodeTable[v2].adj;   NodeTable[v2].adj=q;   numEdges++;   return true;  }     return -1;};template<class T,class E>bool Graphlnk<T,E>::insertEdge1(int v1,int v2,E weight)//插入有向边{     if(v1>=0&&v1<numVertices&&v2>=0&&v2<numVertices)  {      Edge<T,E> *p=NodeTable[v1].adj;   while(p!=NULL&&p->dest!=v2)    p=p->link;   if(p!=NULL)    return false;   p=new Edge<T,E>;   p->dest=v2;   p->cost=weight;   p->link=NodeTable[v1].adj;   NodeTable[v1].adj=p;   numEdges++;   return true;  }     return -1;};template<class T,class E>void Graphlnk<T,E>::Build(Graphlnk<T,E>& G){      int i,j,k,n,m,d;  T e1,e2;  E weight;  cout<<"输入顶点数:"<<endl;  cin>>n;  cout<<"边数:"<<endl;  cin>>m;//顶点,边数  cout<<"1、无向图;2、有向图";  cin>>d;  cout<<"顶点表数据:"<<endl;  for(i=0;i<n;i++)//建立顶点表数据  {   cout<<"第"<<i+1<<"个:";      cin>>e1;   G.insertVertex(e1);  }  i=0;  while(i<m)  {    cout<<"输入第"<<i+1<<"个端点信息(e1,e2,w):";       cin>>e1>>e2>>weight;//输入端点信息    j=G.getVertexPos(e1);    k=G.getVertexPos(e2);//查顶点号    if(j==-1||k==-1)     cout<<"边两端点信息有误,重新输入!"<<endl;    else    {     if(d==0)            G.insertEdge(j,k,weight);     else      G.insertEdge1(j,k,weight);     i++;    }  }};template<class T,class E>void Graphlnk<T,E>::Output(Graphlnk<T,E>& G){     int i,j,n,m;  T e1,e2;  E w;  n=G.NumberOfVertices();  m=G.NumberOfEdges();  cout<<n<<","<<m<<endl;  for(i=0;i<n;i++)   for(j=i+1;j<n;j++)   {      w=G.getWeight(i,j);   if(w>0&&w<maxWeight)   {       e1=G.getValue(i);    e2=G.getValue(j);    cout<<"("<<e1<<","<<e2<<","<<w<<")"<<endl;   }   }};template<class T,class E>void Graphlnk<T,E>::DFS(Graphlnk<T,E>& G,const T& v)//深度优先遍历{     int i,loc,n=G.NumberOfVertices();     bool *visited=new bool[n];  for(i=0;i<n;i++)   visited[i]=false;  loc=G.getVertexPos(v);  DFS(G,loc,visited);  delete []visited;};template<class T,class E>void Graphlnk<T,E>::DFS(Graphlnk<T,E>& G,int v,bool visited[]){     cout<<G.getValue(v)<<" ";  visited[v]=true;     int w=G.getFirstNeighbor(v);  while(w!=-1)  {       if(visited[w]==false)     DFS(G,w,visited);    w=G.getNextNeighbor(v,w);  }};template<class T,class E>void Graphlnk<T,E>::BFS(Graphlnk<T,E>& G,const T& v)//广度优先遍历{     int i,w,n=G.NumberOfVertices();  bool *visited=new bool[n];  for(i=0;i<n;i++)   visited[i]=false;  int loc=G.getVertexPos(v);  cout<<G.getValue(loc)<<" ";  visited[loc]=true;  queue<int>Q;  Q.push(loc);  while(!Q.empty())  {    loc=Q.front();       Q.pop();       w=G.getFirstNeighbor(loc);    while(w!=-1)    {         if(visited[w]==false)      {           cout<<G.getValue(w)<<" ";     visited[w]=true;     Q.push(w);      }      w=G.getNextNeighbor(loc,w);    }  }     delete []visited;};template<class T,class E>void Graphlnk<T,E>::Readfile(Graphlnk<T,E>& G)//从文件中读取图{  ifstream on("graph.txt");  if(!on)  {      cerr<<"Can't open the graph.txt!"<<endl;   exit(1);  }  else  {      cout<<"Read the file successfully!"<<endl;  }     int i,j,k,n,m,d;  T e1,e2;  E weight;  on>>n>>m;//顶点,边数  on>>d;  for(i=0;i<n;i++)//建立顶点表数据  {      on>>e1;   G.insertVertex(e1);  }  i=0;  while(i<m)  {       on>>e1>>e2>>weight;//输入端点信息    j=G.getVertexPos(e1);    k=G.getVertexPos(e2);//查顶点号    if(d==0)      G.insertEdge(j,k,weight);    else     G.insertEdge1(j,k,weight);    i++;  }        on.close();}void main(){    int choice=0; char ch;//遍历的顶点    Graphlnk<char,int>G; while(choice!=6) {   cout<<endl;      cout<<"             图的遍历   "<<endl;      cout<<"1、文件建立图:"<<endl;      cout<<"2、输入建立图:"<<endl;   cout<<"3、图的广度遍历:"<<endl;   cout<<"4、图的深度遍历:"<<endl;   cout<<"5、输出图:"<<endl;   cout<<"6、退出!"<<endl;   cout<<"输入要选择的选项:"<<endl;   cin>>choice;   switch(choice)   {   case 1:G.Readfile(G);break;   case 2:G.Build(G);break;   case 3:    {     cout<<"开始遍历的顶点:";     cin>>ch;     G.BFS(G,ch);     break;    }   case 4:    {     cout<<"开始遍历的顶点:";     cin>>ch;     G.DFS(G,ch);     break;    }   case 5:G.Output(G);break;   default:exit(1);break;   } }}




心得:

         图的遍历,一个不算难得算法,拖了很久,终于做完了。可惜是在数据结构期末考试后,期末有一道是广度遍历的题目,现在明白了,可是考试时不会写...一开始看到这个实验,心里就觉得很难,不想做,这就是我这个人的最大问题。其实做起来和以前的实验差不多,都是搬书上的代码,然后加上一些自己的理解,再经过调试就做出来了。总的来说,2天的时间,算是比较短了。

         有向图、无向图、深度遍历、广度遍历,都不算难,关键是理解代码的运行,切记不要死记硬背!

         C++,从树上得到的知识不经过运行,永远都不会理解的,要多上机,才会理解代码!加油!

原创粉丝点击