无向图的存储以及广度优先搜索.

图的表示

对于图G=(V,E),可以用两种标准方法表示。第一种是将图作为邻接链表的组合,另外一种表示方法是则是将图邻接矩阵来看待。两种表示方法既可以用来表示无向图也可以用来表示有向图,邻接链表的方法在表示稀疏图(边的条数E,远远小于V结点的个数)比较好。比较稠密的图则适合

邻接矩阵的方法.

 #include <iostream>
#include <type_traits>
#include <queue>
namespace{
enum  Color{ white=0, gray=1, black=3 };
}
class Edge{//这里的edge指的是一条边,类似这样 start-------end; start和end都为结点. 
 public:
  int start;
  int end;
  int value;
  Edge* next;
  Edge(const int& s, const int& e, const int& v);
};
Edge::Edge(const int& s, const int& e, const int& v)
     :start(s),
      end(e),
      value(v)
{
 //
}
class Vertex{ //结点的顶点. 
 public:
  Color color;
  int distance; //两个结点之间的距离,相邻的两个结点距离为1.
  int pie;     //储存父结点. 
  Edge* head; //这其实是个顶点被封装在Vertex中. 
  Vertex():color(white),distance(0),pie(0){} //初始化顶点的颜色为白色 标明还没有找到该顶点,初始化顶点 
};
class Graph{
 private:
  int nodeNumber; //无向图中结点的个数.
  Vertex* v; //顶点.
  std::queue<int> que; 
  
  void detroyEdge(Edge* edge);
  void addSingleEdge(const int& start, const int& end, const int& value);
  void deleteSingleEdge(const int& start, const int& end);
  
  public:
  Graph(const int& numberOfNode);
  ~Graph(); 
  
  void addDoubleEdge(const int& start, const int& end, const int& value=1);
  void BFSearch(const int& s); 
  void PrintPath(const int& a, const int& b);
};
Graph::Graph(const int& numberOfNode)
      :nodeNumber(numberOfNode),
       v(nullptr)
{
 this->v = new Vertex[numberOfNode+1];                                     //之所以+1因为树的个数是从1开始数的. 
 std::cout<<"success"<<std::endl;
}
void Graph::addSingleEdge(const int& start, const int& end, const int& value) //存储无向图. 
{
 Edge* newEdge = new Edge(start, end, value);                            //创建一个边 边的左右节点分别为start和end,且start和end之间的距离为value;也就是说他们之间只有一条线连接. 
 
 if(this->v[start].head == nullptr || (this->v[start].head)->end > end){ //这里判断给定的边的顶结点(start)是否存在顶点,且给定结点(start)如果存在顶点那么他的最小节点是否大于newEdge的end(节点) 
  //如果符合上述条件那么令新给的边的顶点(start)成为自身顶点.
   newEdge->next = this->v[start].head; //令v[start]中的顶点 
   this->v[start].head = newEdge;
   
 }else{
  
  Edge* tempEdge = this->v[start].head; //令tempEdge和pre都等于当前顶点. 
  Edge* pre = tempEdge;
  while(newEdge != nullptr && newEdge->end < end){ //树可能很深 因此要用while. 
   pre = newEdge; //注意跳出循环的时候pre总是等于e的head. 
   newEdge = newEdge->next;
  }
  
  if(newEdge != nullptr && newEdge->end == end){
   delete newEdge;
   return;
  }
  
  newEdge->next = newEdge;//把新节点插入到合适的位置. 
  pre->next = newEdge;
 } 
}
void Graph::addDoubleEdge(const int& start, const int& end, const int& value)
{
 this->addSingleEdge(start, end, value); //以start为新建边的顶点. 
 this->addSingleEdge(end, start, value); //以end为新建边的顶点。 
}
void Graph::deleteSingleEdge(const int& start, const int& end)
{
 Edge* e = this->v[start].head;
 Edge* pre = e; //此时pre和e都指向顶点.
 
 while(e != nullptr && e->end < end){ //注意此处这里寻找小于边(start------end)中end的那个结点. 
  pre = e;
  e = e->next;
 } 
 
 if(e == nullptr || e->end > end){ //此时说明给定的结点end是不存在无向图中的. 
  return;
 }
 
 if(e == this->v[start].head){
  this->v[start].head = e->next;
  
 }else{
  pre->next = e->next;
 }
 
 delete e; //销毁e. 
}
void Graph::BFSearch(const int& s) //广度最优搜索. 
{
 int i;
 for(i=1; i<this->nodeNumber; ++i){ //把每个结点的颜色都设置为white; 
  this->v[i].color = ::white;
   this->v[i].distance = 0x7fffffff; //注意这里的 0xffffff为long int的最大值.
   this->v[i].pie = 0;            // pie表示的是当前结点的父节点. 
 }
 
 this->v[s].color = ::gray;         //设置源结点的颜色为gray; 
 this->v[s].distance = 0x7fffffff;  //设置源结点的distance为一个无穷大的数. 
 this->v[s].pie = 0;                //设置源结点的父节点为空(0)。 
  
  while(!que.empty()){
   this->que.pop();              //栈内元素清空. 
  }
  
  this->que.push(s);              //把源结点s。放到栈内. 
  while( !this->que.empty() ){
   int u;
   int tempV;
   
   u = this->que.front();     //读取栈内的源结点. 
   this->que.pop();
   Edge* e = this->v[u].head; 
   
   while( e != nullptr ){   
    tempV = e->end;       //令tempV = 源结点的一个子结点. 
    if(this->v[tempV].color == ::white){ //如果该子节点的颜色为white 
     this->v[tempV].color = ::gray;
     this->v[tempV].distance = this->v[u].distance + 1;
     this->v[tempV].pie = u;
     this->que.push(tempV);
     
    }
    
    e = e->next;
   }
   
   this->v[u].color = ::black;
     }
 
}
void Graph::PrintPath(const int& a, const int& b) //输出结点a到结点b之间的所有结点. 
{
 this->BFSearch(a); //设置源节点为a. 
 if(a == b){       //当结点a与结点b相同的时候那么就没有再继续寻找的意义了所以路过的结点就只有a. 
  std::cout<<a<<"   ";
  
 }else{
  if(this->v[b].pie == 0){ //判断节点b是否含有父结点. 如果没有父结点那么b点就不存在无向图中. 
   std::cout<<"no path from "<<a<<" to "<<b;
   
  }else{                  //存在父结点那么寻找a,到b的父节点之间经过的所有结点. 
   this->PrintPath(a, this->v[b].pie);
   std::cout<<b<<"  ";
   
  }
  
 }
}
void Graph::detroyEdge(Edge* edge)
{
 Edge* e = edge->next;
 delete edge;
 edge = nullptr;
 if(e != nullptr){
  this->detroyEdge(e);
 }
 
 return;
}
Graph::~Graph()
{
 while(!this->que.empty()){
  this->que.pop();
 }
 
 if(this->v != nullptr){
  for(int i=1; i<=this->nodeNumber; ++i){
   if(this->v[i].head != nullptr){
    Edge* tempEdge = this->v[i].head;
    this->detroyEdge(tempEdge);
   }
  }
 }
}
int main()
{
/* 
1 2 
1 5 
2 6 
6 7 
6 3 
3 7 
3 4 
7 8 
7 4 
4 8 
*/
Graph* myGraph = new Graph(int(8)); //这里的8指的是结点的个数.
int a;
int b;
 for(int i=0; i<=8; ++i){
  std::cin>>a>>b;
  myGraph->addDoubleEdge(a, b);
 }
 
 myGraph->BFSearch(2); //当给定源结点为2的时候所有节点的父节点.
int s=2; 
int e=4;
myGraph->PrintPath(s, e);
return 0;
}

 

你可能感兴趣的:(无向图的存储以及广度优先搜索.)