图的遍历

题目 图的遍历

 

【问题描述】
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++,从树上得到的知识不经过运行,永远都不会理解的,要多上机,才会理解代码!加油!

    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/zhihang527548263/article/details/12068909
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞