图的表现和实现2(邻接矩阵表表示法)

来源:互联网 发布:linux 文件夹映射 编辑:程序博客网 时间:2024/06/06 07:23

     邻接表:

         顶点表的每个元素存储顶点信息,由俩个域成,data(数据域)和adjlink(与顶点关联的边对应的单链表)边链表中的结点由3个域组成,dest.weight和next,其中dest域根据无向图或者有向图而不同,weight域在非带权图中将被省略。

        无向图的邻接表表示:

      在边表中,第i行单链表存储所有与顶点vi相关联的边,每个边结点存储从顶点vi到vj的一条边(vi,vj),dest域是该条边的终点vj在顶点表的序号,weight域存储边的权值,next域指向与vi相关联的下一条边对应的结点。注意:无向图的邻接表将每条边分别存储在与该边关联的俩个顶点的边表中,故而存储了俩次

    有向图的邻接表表示:

     对于有向图来说,vi的邻接表中每个表结点都对应于以vi为始点射出的一条边。因此,有向图的边表也称为出边表。  有向图还有一种称为逆邻接表表示法,该方法为图中每个顶点vi建立一个入边表,入边表中的每个表结点均对应一条以vi为终点的边。

     


     邻接表的带权图类:

     顶点表图类:data表示顶点数据域,数据类型为T;adjlink表示顶点的边单链表,边结点的data域的数据类型为Edge结构体

      

#include "Edage.h"#include "SingleLinkedList.h"using namespace std;template<class T>    //不带头结点的单链表类struct Vertex{   T data;   //顶点数据域   SingleLinkedList<Edge>   adjlink;  //该顶点的边单链表};

        邻接表表示的带权图类:vertexlist是存储顶点的动态数组,size是顶点表数组容量;verCount是图的顶点数

         

#include "Vertex.h"#include "AbstractGraph.h"  //抽象图类template<class T>class AdjListGraph:public AbstractGraph<T>  //邻接表表示的带权图类,继承抽象图类{private:Vertex<T> *vertexlist;  //顶点表数组int size;  //顶点表数组容量int vertcount;  //顶点数,vertCount<=sizepublic:AdjListGraph(int size=10); //构造方法,sizeAdjListGraph(T vertices[],int vertcount,Edge edges[],int edgeCount);   //以顶点集合和边集合构造一个图~AdjListGraph();int VertexCount();  //返回顶点数T Get(int i);  //返回顶点vi的数据元素void InsertVertex(T vertex);  //插入一个顶点bool InsertEdge(int i,int j,int weight);  //插入一条权值为weight的边bool InsertEdge(Edge edge);  //插入一条边friend ostream& operator<<(ostream& out,AdjListGraph<T> &graph);  //输出图的顶点集和和邻接表bool RemoveEdge(int i,int j);  //删除边指定顶点序号bool RemoveVertex(int v, T &old);  //删除序号为v的顶点及其相关联的边int GetFirstNeighbor(int v);  //返回顶点v的第一个邻接顶点的序号int GetNextNeighbor(int v,int w);  //返回v在w后的下一个邻接顶点的序号};
             

       图的构造和析构函数:

template<class T>AdjListGraph<T> ::~AdjListGraph(){    delete [] vertexlist;}template<class T>AdjListGraph<T>::VertexCount(){   return vertcount;}template<class T>T AdjListGraph<T>::Get(int i){  if(i>=0&&i<vertcounT)  return vertexlist[i].data;  throw "参数i指定元素序号无效";}template<class T>ostream& operator<<(ostream& out,AdjListGraph<T>& graph){for(int i = 0;i<graph.vertcount;i++){out<<i<<" "<<"顶点"<<graph.vertexlist[i].data<<"  出边表:";out<<graph.vertexlist[i].adjlink;  //输出第i条单链表}return out;}
       图的插入操作:在邻接表表示的图中插入一个顶点,就是在顶点表数组vertexlist最后插入一个元素,如果数组容量不够,需重新申请数组空间,扩充数组。
template<class T>void AdjListGraph<T>::InsertVertex(T vertex)  //插入一个顶点{   if(vertcount == size)  //顶点表若数组满,则扩充   {      Vertex<T> *temp = verexlist;  vertexlist = new Vertex<T> [size*2];  for(int i = 0;i<size;i++)  vertexlist[i] = temp [i];  size*=2;   }   vertexlist[vertcount].data = vertex;  //在顶点表最后插入一个元素   vertcount++;}
        

         在邻接表表示的图中插入一条边,,结点的data域是一个Edge结构体,若该边已存在,则不插入,因此需要在单链表中进行查找。为了提高查找效率,将边单链表设计为排序的单链表,结点按照边的dest域升序排序。

         

template<class T>bool AdjListGraph<T>::InsertEdge(int i, int j, int weight){    if(i>=0&&i<vertcount&&j>=0&&j<vertcount&&i!=j){Edge e = {i,j,weight};SingleNode<Edge> *p= vertexlist[i].adjlink.head,*front;if(p==NULL||p!=NULL&&j<p->data.dest)  //头插法{vertexlist[i].adjlink.head = new SingleNode<Edge>(e,p);return true;}while(p!=NULL&&j>=p->data.dest){if(j==p->data.dest)  //若该边已存在,则不插入return false;front = p;p = p->next;}front->next = new SingleNode<Edge> (e,p);  //中间或尾插入return true;}return false;}template<class T>bool AdjListGraph<T>::InsertEdge(Edge edge)  //插入一条边{return InsertEdge(edge.start,edge.dest,edge.weight);}
        图的删除操作:在邻接表表示的图中删除一条边,就是删除单链表中dest域为j的结点,忽略其权值   

        

template<class T>bool AdjListGraph<T>::RemoveEdge(int i, int j) //删除边{   if(i>=0&&i<vertcount&&j>=0&&j<vertcount&&i!=j)   {   SingleNode<Edge> *p = vertexlist[i].adjlink.head,*front;   if(p!=NULL&&p->data.dest == j)  //头删除   {   vertexlist[i].adjlink.head = p->next;   delete p;   return true;   }   while(p!=NULL&&p->date.dest!=j)  //在第i条单链表中寻找指定结点   {      front = p;  p = p->next;   }   if(p!=NULL)   {   front->next = p->next;   delete p;   return true;   }   }   return false;}
       删除一个顶点分3步(1)在顶点表中删除指定顶点vi,一行(2)在所有边单链表中,删除与顶点vi相关联的所有边结点。(3)原序号在vi之后的顶点,其在边表中的顶点序号减1。

 

template<class T>bool AdjListGraph<T>::RemoveVertex(int v, T &old)  //删除序号为v的顶点及其相关联的边{   if(v<0||v>=vertcount)   return false;   SingleNode<Edge> *p = vertexlist[v].adjlink.head;  //获得欲删除的第v条边的单链表   while(p!=NULL)   {     RemoveEdge(p->data.dest,p->data.start);  //删除对称的边 p= p->next;   }   old = vertexlist[v].data;   vertexlist[v].adjlink.ClearList();   int i;   for(i = v;i<vertcount-1;i++)   {   vertexlist[i].data = vertexlist[i+1].data;   vertexlist[i].adjlink.head = vertexlist[i+1].adjlink.head;   vertexlist[i+1].adjlink.head =NULL;   }   vertcount--;  //顶点数减1   for(i=0;i<vertcount;i++)  //未删除的边结点更改某些顶点序号   {   p = vertexlist[i].adjlink.head;  //获得第i条边单链表   while(p!=NULL)   {     if(p->data.start>v) p->data.start--; if(p->data.dest>v) p->data.dest--; p = p->next;   }   }    return true;}