C++实现无向图
本篇主要记录一下最近学习的较简单的无向图实现,主要参考了《算法》第四版中关于图的内容。
该无向图支持自环但不支持平行边,日后慢慢优化吧。
首先我们知道图是由一组顶点和一组能够将两个顶点相连的边组成。这里我们定义一个顶点类,顶点类中有该顶点的value以及该顶点的邻居顶点的集合,这个集合对应了在《算法》书中使用了bag类的对象,本篇使用C++的list类似乎也问题没那么大。最后一个成员变量是该顶点的度数,度数在无向图中可以理解为顶点的邻节点数量。下面是顶点类的定义:
class Vertex
{
public:
Vertex(int val)
{
in_out = 0;
value = val;
};
int value;
int in_out;
list<Vertex *> neighbours;
};
因为在无向图中,边只是两个顶点的连接,因此就先不给边定义一个专门的类了,用顶点类的邻居节点就可以表示出边的情况。
接下来可以利用这个顶点类来构造一个无向图类undirect_Graph了。
首先需要定义一个构造函数,这个构造函数应该可以将图这种结构表示出来,本篇还是沿用《算法》书里的方法,读取一个txt文件,该文件第一行的数字表示这个图的顶点数,第二行的数字表示这个图包含的边数,剩余每一行的数据都是成对出现,代表相连的两个顶点,如下所示:
读取方法如下所示:
undirect_Graph::undirect_Graph(string path)
{
ifstream data(path);
int dat;
data >> dat;
cout << "the count of Vertex : " << dat << " ";
m_countOfVertex =dat;
data >> dat;
cout << "the count of Edge : " << dat << " ";
m_countOfEdge = dat;
cout << endl;
// neighbourVertexs = vector<Vertex *>(m_countOfVertex);
for(int index = 0; index < m_countOfEdge; index++)
{
cout << "读取顶点: " ;
data >> dat;
cout << dat << " ";
int firstVertex = dat;
cout << "读取顶点: " ;
data >> dat;
cout << dat << endl;
int secondVertex = dat;
addEdge(firstVertex, secondVertex);
}
}
void undirect_Graph::addEdge(int firstVertex, int secondVertex)
{
Vertex *firstVertexNode = new Vertex(firstVertex);
Vertex *secondVertexNode = new Vertex(secondVertex);
firstVertexNode->neighbours.push_back(secondVertexNode);
firstVertexNode->in_out++;
secondVertexNode->neighbours.push_back(firstVertexNode);
secondVertexNode->in_out++;
pair<int, Vertex*> v(firstVertex, firstVertexNode);
pair<int, Vertex*> w(secondVertex, secondVertexNode);
if (!isInserted(firstVertex, VertexSet))
{
VertexSet.insert(v);
}
else
{
VertexSet[firstVertex]->neighbours.push_back(secondVertexNode);
}
if(!isInserted(secondVertex, VertexSet))
{
VertexSet.insert(w);
}
else
{
VertexSet[secondVertex]->neighbours.push_back(firstVertexNode);
}
}
调用这个无向图的构造函数之后,我们可以从无向图对象中获取该图的边数、顶点数,以及顶点集合,这个顶点集合里每个顶点对象都包含有该顶点的邻居顶点集合,在搜索时就可以访问每个顶点对象中的邻居顶点了。而利用上面的测试用例,我们定义一个undirect_Graph对象后就可以得到如下图所示的一个无向图结构。
int main(){
string path = "graph_initial.txt";
undirect_Graph graph(path);
graph.print_allVertexAndEdge();
DepthFirstGraph dfg(graph, 0);
cout << dfg.getCount() << endl;
return 0;
}
其他一些基本的图算法函数比较简单就不多赘述,如打印出图中节点与节点的连接情况等。
全部代码如下所示:
//
// Graph_practise.hpp
// Dat_Structure
//
// Created by 云子谣 on 2020/4/10.
// Copyright © 2020 云子谣. All rights reserved.
//
#ifndef Graph_practise_hpp
#define Graph_practise_hpp
#include <stdio.h>
#include <vector>
#include <iostream>
#include <string>
#include <fstream>
#include <map>
#include <set>
#include <list>
using namespace std;
#endif /* Graph_practise_hpp */
//顶点类
class Vertex
{
public:
Vertex(int val)
{
in_out = 0;
value = val;
};
int value;
int in_out;
list<Vertex *> neighbours;
};
class undirect_Graph
{
public:
undirect_Graph(string path);
int countOfVertex(); //获得顶点数
int countOfEdge(); // 边数
void addEdge(int firstVertex, int secondVertex);
void print_allVertexAndEdge();
map<int, Vertex*> getGraphVertexSet();
private:
int m_countOfVertex;
int m_countOfEdge;
map<int, Vertex *> VertexSet;
bool isInserted(int v, map<int, Vertex*> VertexSet);
// vector<Vertex *> neighbourVertexs;
};
//
// Graph_practise.cpp
// Dat_Structure
//
// Created by 云子谣 on 2020/4/10.
// Copyright © 2020 云子谣. All rights reserved.
#include "Graph_practise.hpp"
undirect_Graph::undirect_Graph(string path)
{
ifstream data(path);
int dat;
data >> dat;
cout << "the count of Vertex : " << dat << " ";
m_countOfVertex =dat;
data >> dat;
cout << "the count of Edge : " << dat << " ";
m_countOfEdge = dat;
cout << endl;
// neighbourVertexs = vector<Vertex *>(m_countOfVertex);
for(int index = 0; index < m_countOfEdge; index++)
{
cout << "读取顶点: " ;
data >> dat;
cout << dat << " ";
int firstVertex = dat;
cout << "读取顶点: " ;
data >> dat;
cout << dat << endl;
int secondVertex = dat;
addEdge(firstVertex, secondVertex);
}
}
void undirect_Graph::addEdge(int firstVertex, int secondVertex)
{
Vertex *firstVertexNode = new Vertex(firstVertex);
Vertex *secondVertexNode = new Vertex(secondVertex);
firstVertexNode->neighbours.push_back(secondVertexNode);
firstVertexNode->in_out++;
secondVertexNode->neighbours.push_back(firstVertexNode);
secondVertexNode->in_out++;
pair<int, Vertex*> v(firstVertex, firstVertexNode);
pair<int, Vertex*> w(secondVertex, secondVertexNode);
if (!isInserted(firstVertex, VertexSet))
{
VertexSet.insert(v);
}
else
{
VertexSet[firstVertex]->neighbours.push_back(secondVertexNode);
}
if(!isInserted(secondVertex, VertexSet))
{
VertexSet.insert(w);
}
else
{
VertexSet[secondVertex]->neighbours.push_back(firstVertexNode);
}
}
bool undirect_Graph::isInserted(int v, map<int, Vertex *> VertexSet)
{
map<int, Vertex*>::iterator iter = VertexSet.begin();
for(iter; iter != VertexSet.end(); iter++)
{
if(iter->first == v)
return true;
}
return false;
}
void undirect_Graph::print_allVertexAndEdge()
{
map<int, Vertex*>::iterator iter = VertexSet.begin();
for(iter; iter != VertexSet.end(); iter++)
{
cout << "顶点" << iter->first << "的邻节点:";
for(list<Vertex*>::iterator j = iter->second->neighbours.begin(); j != iter->second->neighbours.end(); j++)
{
cout << (*j)->value << " ";
}
cout << endl;
}
}
map<int, Vertex*> undirect_Graph::getGraphVertexSet()
{
return VertexSet;
}
int undirect_Graph::countOfVertex()
{
return m_countOfVertex;
}
下篇主要是基于这个无向图记录一下深度优先搜索算法的实现过程。