Directorio de artículos
matriz de adyacencia gráfica
namespace Graph_Structure
{
//Vertex是代表顶点的数据类型,Weight是边的权值的数据类型,MAX_W是权值的上限值(表示不相两)
//Direction表示图是否为有向图
template<class Vertex, class Weight = int, Weight MAX_W = INT_MAX, bool Direction = false>
class Graph
{
typedef Graph<Vertex, Weight, MAX_W, Direction> Self;
public:
//使用编译器的默认构造函数
Graph() = default;
//给定一个存放顶点的数组用来初始化图
Graph(const Vertex* a, size_t n)
{
_vertexs.reserve(n);
_indexMap.rehash(n);
_matrix.resize(n, std::vector<Weight>(n, MAX_W));
for (size_t i = 0; i < n; ++i)
{
_vertexs.push_back(a[i]);
//建立顶点和数组下标的映射(目的是为了邻接矩阵的边存储)
_indexMap[a[i]] = i;
}
}
//获取顶点在邻接矩阵中对应的下标
size_t GetVertexIndex(const Vertex& vertex)
{
if (_indexMap.find(vertex) == _indexMap.end())
{
throw "invalued_para";
return -1;
}
return _indexMap[vertex];
}
void _AddEdge(size_t srci, size_t dsti, const Weight& w)
{
//判断是有向图还是无向图
if (Direction == false)
{
_matrix[dsti][srci] = w;
}
_matrix[srci][dsti] = w;
}
//给定起点和终点,在邻接矩阵中添加一条边
void AddEdge(const Vertex& src, const Vertex& dst, const Weight& w)
{
if (_indexMap.find(src) == _indexMap.end() || _indexMap.find(dst) == _indexMap.end())
{
throw "invalued_para";
}
size_t srci_index = GetVertexIndex(src);
size_t dst_index = GetVertexIndex(dst);
_AddEdge(srci_index, dst_index, w);
}
//将图的邻接矩阵打印出来
void Print()
{
for (auto e : _vertexs)
{
std::cout << e << '[' << _indexMap[e] << ']' << std::endl;
}
std::cout << " ";
for (int i = 0; i < _vertexs.size(); ++i)
{
std::cout << i << " ";
}
std::cout << std::endl;
int i = 0;
for (auto arry : _matrix)
{
std::cout << i++ << ' ';
for (auto e : arry)
{
if (e == MAX_W)
{
printf("%4c ", '*');
}
else
{
printf("%4d ", e);
}
}
std::cout << std::endl;
}
}
//图的广度优先遍历
void BFS(const Vertex& src)
{
size_t begin = GetVertexIndex(src);
std::queue<int> QNode;
std::vector<bool> Label(_vertexs.size(), false);
QNode.push(begin);
Label[begin] = true;
size_t Level = 0;
while (!QNode.empty())
{
size_t LevelSize = QNode.size();
for (size_t i = 0; i < LevelSize; ++i)
{
size_t front = QNode.front();
QNode.pop();
std::cout << _vertexs[front] << '[' << front << ']' << std::endl;
for (int j = 0; j < _vertexs.size(); ++j)
{
if (Label[j] == false && _matrix[front][j] != MAX_W)
{
QNode.push(j);
Label[j] = true;
}
}
}
}
}
//图的深度优先遍历
void DFS(const Vertex& src)
{
std::vector<bool> visited(_vertexs.size(), false);
_DFS(GetVertexIndex(src), visited);
}
private:
void _DFS(size_t srci, std::vector<bool>& visited)
{
visited[srci] = true;
std::cout << _vertexs[srci] << '[' << srci << ']' << std::endl;
for (int i = 0; i < _vertexs.size(); ++i)
{
if (_matrix[srci][i] != MAX_W && visited[i] == false)
{
_DFS(i, visited);
}
}
}
private:
std::vector<Vertex> _vertexs; // 顶点集合
std::unordered_map<Vertex, size_t> _indexMap; // 顶点映射下标
std::vector<std::vector<Weight>> _matrix; // 邻接矩阵
};
}
existirGráfico ponderado dirigidoDado un vértice inicial (punto fuente) en , el algoritmo de Dijkstra puede encontrartodos los demás vérticesEl camino más corto hasta la fuente, el algoritmo de DijkstraNo se puede utilizar para gráficos que contengan aristas con pesos tanto positivos como negativos.
1. Análisis del algoritmo de Dijkstra
Los elementos lógicos centrales del algoritmo.
Source
Conjunto de vértices: determinadocamino más corto a la fuenteLos vértices del conjunto se agregaránSource
al conjunto ySource
el conjunto inicialmente solo tiene el punto fuente.dist
Matriz: utilizada para registrar la distancia desde cada vértice hasta el punto de origen,dist
la matriz tiene las siguientes propiedades:- paraexistir en
Source
la colecciónEl vértice de,dist
el valor correspondiente de este vértice en la matriz esLa distancia desde el vértice hasta el camino más corto desde el punto de origen.(una clase de vértices) - parano
Source
en conjuntoperoSource
directamente conectado a la colecciónEl vértice de,dist
el valor correspondiente de este vértice en la matriz esSource
La distancia del camino más corto desde el vértice hasta la fuente a través de la colección.(vértices de segunda clase) - parano
Source
en conjuntoynoSource
conectado directamente a la colecciónvértice,dist
el valor correspondiente de este vértice en la matriz es infinito (tres tipos de vértices)
- paraexistir en
Lógica de ejecución del algoritmo
- Es fácil demostrar que
dist
mientras la matriz mantenga las propiedades anteriores, entonces, en el segundo tipo de vértices,dist
vértice con el valor más pequeñoPuede unirseSource
al conjunto y el valor mínimo es la distancia más corta desde el vértice hasta el punto de origen. - Cada vez que se agrega un vértice al conjunto, la matriz se actualiza
Source
en función de ese vértice.dist
mantener su naturaleza original - Repita esto hasta que todos los vértices del gráfico se agreguen al
Source
conjunto ydist
la matriz registre losLa distancia más corta desde todos los vértices hasta el punto de origen..
2. Implementación de la interfaz del algoritmo de Dijkstra
//单源最短路径算法,src为起始顶点(源点)
//dist用于记录各顶点到源点的距离
//parentPath用于记录最短路径中各顶点的前驱顶点
void Dijkstra(const Vertex& src, std::vector<Weight>& dist, std::vector<int>& parentPath)
{
dist.resize(_vertexs.size(), MAX_W);
parentPath.resize(_vertexs.size(), -1);
//用于标记Source集合中顶点的表,初始时只有源点在其中
std::vector<bool> Source(_vertexs.size(), false);
int srcindex = GetVertexIndex(src);
dist[srcindex] = 0; //源点自己到自己的距离为0
//图共有多少个顶点就执行多少次循环
for (int i = 0; i < _vertexs.size(); ++i)
{
//从dist数组中选出距离源点最近的二类顶点加入到Source集合中
int MinWeight = MAX_W;
int Minindex = -1;
for (int j = 0; j < dist.size(); ++j)
{
if (Source[j] == false && dist[j] < MinWeight)
{
MinWeight = dist[j];
Minindex = j;
}
}
//将顶点加入Source集合中
Source[Minindex] = true;
//更新与Source集合直接相连且不在Source集合中的顶点距离源点的距离(dist数组的更新)
for (int j = 0; j < _matrix.size(); ++j)
{
if (_matrix[Minindex][j] != MAX_W &&
Source[j] == false && _matrix[Minindex][j] + dist[Minindex] < dist[j])
{
dist[j] = _matrix[Minindex][j] + dist[Minindex];
//记录顶点前驱
parentPath[j] = Minindex;
}
}
}
}
- La matriz en la interfaz
parentPath
se utiliza para grabar.El vértice predecesor de cada vértice en el camino más corto., una vez finalizado el algoritmo,parentPath
cada ruta más corta se puede obtener completamente con la ayuda de la matriz
Versión optimizada del montón de matriz de adyacencia:
- Seleccionar de
dist
la matrizEl vértice tipo II más cercano al punto fuente.Este proceso se puede realizar con la ayuda de un montón, una versión optimizada del montón de matriz de adyacencia:
//堆优化版本
struct vertex_dist
{
int _dest;
Weight _v_source;
vertex_dist(int dest,Weight v_source)
:_dest(dest),
_v_source(v_source){
}
//小堆比较运算符
bool operator>(const vertex_dist& v_d) const
{
return _v_source > v_d._v_source;
}
};
void Dijkstra_heap(const Vertex& src, std::vector<Weight>& dist, std::vector<int>& parentPath)
{
dist.resize(_vertexs.size(), MAX_W);
parentPath.resize(_vertexs.size(), -1);
//用于标记Source集合中顶点的表,初始时只有源点在其中
std::vector<bool> Source(_vertexs.size(), false);
int srcindex = GetVertexIndex(src);
dist[srcindex] = 0; //源点自己到自己的距离为0
//创建小堆
std::priority_queue<vertex_dist, std::vector<vertex_dist>, std::greater<vertex_dist>> Heap;
Heap.push(vertex_dist(srcindex, 0));
while (!Heap.empty())
{
vertex_dist Smallest = Heap.top();
Heap.pop();
//若顶点已经在Source集合中则跳过
if (Source[Smallest._dest]) continue;
//将顶点加入Source集合中
Source[Smallest._dest] = true;
for (int i = 0; i < _vertexs.size(); ++i)
{
if (_matrix[Smallest._dest][i] != MAX_W &&
Source[i] == false && _matrix[Smallest._dest][i] + dist[Smallest._dest] < dist[i])
{
dist[i] = _matrix[Smallest._dest][i] + dist[Smallest._dest];
Heap.push(vertex_dist(i, dist[i]));
//记录顶点前驱
parentPath[i] = Smallest._dest;
}
}
}
}
- La versión optimizada del montón de matrices de adyacencia no reduce la complejidad temporal del algoritmo (todavía lo es
O(N^2)
), para reducir la complejidad temporal del algoritmo de Dijkstra, utiliceEstructura de almacenamiento de lista de adyacenciaoEstructura de almacenamiento en cadena en estrella delantera.(con optimización del montón) puede reducir la complejidad aO(mlogn)
(n
representa el número de puntos,m
representa el número de aristas)