图是由一组顶点和一组能够将两个顶点相连的边组成的。无向图的边仅仅是两个顶点之间的连接,没有方向。
当且仅当一幅含有V个节点的图G满足下列5个条件之一时,它就是一棵树:
l G有V-1条边且不含环
l G有V-1条边且是连通的
l G是连通的,但删除任意一条边都会使它不再连通
l G是无环图,但添加任意一条边都会产生一条环
l G中任意一对顶点之间仅存在一条简单路径
图的几种表示方法
l 邻接矩阵。使用V*V的布尔矩阵,当顶点v和顶点w之间有连接的边时,定义v行w列的元素值为true,都则为false。
l 邻接表。可以使用一个以顶点为索引的列表数组,其中每个元素都是和该顶点相邻的顶点列表。
以下是邻接表的数据结构图示。
使用邻接表数据结构的Graph源代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Graph
{
public:
Graph(size_t n) : arr(n), edges(0), vertaxs(n) {}
void addEdge(size_t a, size_t b);
void removeEdge(size_t a, size_t b);
void addVertax(size_t n);
void removeVertax(size_t n);
vector<size_t> adj(size_t n) const;
void showAdj(size_t n) const;
void showGraph() const;
size_t edge() const { return edges; }
size_t vertax() const { return vertaxs; }
private:
vector<vector<size_t>> arr;
size_t edges;
size_t vertaxs;
};
int main(void)
{
Graph graph(5);
graph.addEdge(0, 1);
graph.addEdge(3, 4);
graph.addEdge(1, 3);
graph.addEdge(0, 4);
graph.addEdge(2, 3);
graph.addEdge(0, 2);
cout << graph.vertax() << endl;
cout << graph.edge() << endl;
graph.showGraph();
graph.removeEdge(0, 4);
cout << endl;
cout << graph.vertax() << endl;
cout << graph.edge() << endl;
graph.showGraph();
graph.addVertax(5);
cout << endl;
cout << graph.vertax() << endl;
cout << graph.edge() << endl;
graph.showGraph();
graph.removeVertax(3);
cout << endl;
cout << graph.vertax() << endl;
cout << graph.edge() << endl;
graph.showGraph();
system("pause");
return 0;
}
void Graph::addEdge(size_t a, size_t b)
{
if (!(a < arr.size() && b < arr.size()))
return;
arr[a].push_back(b);
arr[b].push_back(a);
edges++; // 无向图
}
void Graph::removeEdge(size_t a, size_t b)
{
if (!(a < arr.size() && b < arr.size()))
return;
vector<size_t>::iterator iter;
iter = find(arr[a].begin(), arr[a].end(), b);
if (iter != arr[a].end())
{
arr[a].erase(iter);
//edges--;
}
iter = find(arr[b].begin(), arr[b].end(), a);
if (iter != arr[b].end())
{
arr[b].erase(iter);
edges--;
}
}
void Graph::addVertax(size_t n)
{
if (n != arr.size())
return;
arr.push_back(vector<size_t>());
vertaxs++;
}
void Graph::removeVertax(size_t n)
{
if (n >= arr.size())
return;
while (!arr[n].empty())
removeEdge(n, arr[n][0]); // 调用removeEdge函数,不用考虑分两次删除边了
//arr.erase(arr.begin() + n);
vertaxs--;
}
vector<size_t> Graph::adj(size_t n) const
{
if (n < arr.size())
return arr[n];
else
return vector<size_t>();
}
void Graph::showAdj(size_t n) const
{
if (n >= arr.size())
return;
vector<size_t> vec;
vec = adj(n);
for (size_t i = 0; i < vec.size(); i++)
cout << vec[i] << " ";
cout << endl;
}
void Graph::showGraph() const
{
for (size_t i = 0; i < arr.size(); i++)
{
cout << i << ": ";
showAdj(i);
}
}
参考:
1、https://github.com/luoxn28/algorithm_data_structure (里面有常用的数据结构源代码)
2、算法(第4版) 无向图章节