最短路径
指定源点的最短路径
算法性质
算法性质
算法对关联的图的要求:无要求,任意权重图均可。
算法性质:
可求得图G所有s可达节点p,s~p的一条最短路径。
接口设计
template<typename Key, typename Value>
class ShorestPath
{
public:
class Node;
typename typedef DataStruct::GraphStruct::Graph<Key, Value> InnerGraph;
typename typedef DataStruct::Tree::SortedBalanceBinaryTree<Key, Node*> InnerTree;
class Node
{
public:
double GetDistance()
{
return m_nDistance;
}
typename InnerGraph::Node* GetGraphNode()
{
return m_pGraphNode;
}
Node* GetPreNode()
{
return m_pPreNode;
}
private:
Node()
{
m_nDistance = -1.0;
m_pGraphNode = nullptr;
m_pPreNode = nullptr;
}
Node(typename InnerGraph::Node* pGraphNode_)
{
m_nDistance = -1.0;
m_pGraphNode = pGraphNode_;
m_pPreNode = nullptr;
}
~Node()
{
}
void Reset()
{
m_pPreNode = nullptr;
m_nDistance = -1.0;
}
private:
double m_nDistance;
typename InnerGraph::Node* m_pGraphNode;
Node* m_pPreNode;
friend class ShorestPath;
};
ShorestPath(const InnerGraph& nGraph_);
~ShorestPath();
DataStruct::Array::DynArray<Node*> Run(const Key& nSourceKey_);
private:
const InnerGraph& m_nGraph;
InnerTree m_nNodeMappingTree;
};
实现
构造
template<typename Key, typename Value>
ShorestPath<Key, Value>::ShorestPath(const InnerGraph& nGraph_)
: m_nGraph(nGraph_)
{
DataStruct::Array::DynArray<typename InnerGraph::Node*> _arrGraphNodes = m_nGraph.GetNodesArray();
for (int _i = 0; _i < _arrGraphNodes.GetSize(); _i++)
{
Node* _pNode = nullptr;
try
{
_pNode = new Node(_arrGraphNodes[_i]);
}
catch (...)
{
_pNode = nullptr;
throw "out of memory";
}
InnerTree::Pair _nPair;
_nPair.m_nKey = _arrGraphNodes[_i]->GetPair().m_nKey;
_nPair.m_nValue = _pNode;
m_nNodeMappingTree.Add(_nPair);
}
}
析构
template<typename Key, typename Value>
ShorestPath<Key, Value>::~ShorestPath()
{
}
算法实现
template<typename Key, typename Value>
DataStruct::Array::DynArray<typename ShorestPath<Key, Value>::Node*> ShorestPath<Key, Value>::Run(const Key& nSourceKey_)
{
InnerGraph::Node* _pGraphNode = m_nGraph.SearchNode(nSourceKey_);
if (_pGraphNode == nullptr)
{
throw "can not find key in graph";
}
DataStruct::Array::DynArray<Node*> _arrpNodes;
DataStruct::Array::DynArray<InnerTree::Pair>_arrTreePairs = m_nNodeMappingTree.GetArray();
for (int _i = 0; _i < _arrTreePairs.GetSize(); _i++)
{
_arrpNodes.Add(_arrTreePairs[_i].m_nValue);
_arrpNodes[_i]->Reset();
}
DataStruct::Array::DynArray<typename InnerGraph::Node*> _arrGraphNodes = m_nGraph.GetNodesArray();
DataStruct::Array::DynArray<typename InnerGraph::Edge*> _arrGraphEdges = m_nGraph.GetEdgesArray();
for (int _i = 0; _i < _arrGraphNodes.GetSize(); _i++)
{
for (int _j = 0; _j < _arrGraphEdges.GetSize(); _j++)
{
InnerGraph::EdgeIdentity _nIndentity = _arrGraphEdges[_j]->GetIdentity();
Node* _pNode = nullptr;
m_nNodeMappingTree.Search(_nIndentity.m_nStartKey, _pNode);
if (_pNode == nullptr)
{
throw "cannot find key in tree";
}
if (_pNode->m_pPreNode == nullptr
&& _pNode->m_pGraphNode != _pGraphNode)
{
continue;
}
if (_pNode->m_pGraphNode == _pGraphNode)
{
_pNode->m_nDistance = 0;
}
Node* _pNode2 = nullptr;
m_nNodeMappingTree.Search(_nIndentity.m_nEndKey, _pNode2);
if (_pNode2 == nullptr)
{
throw "can not find key in tree";
}
if ((_pNode2->m_pPreNode == nullptr
&& _pNode2->m_pGraphNode != _pGraphNode)
|| (_pNode->m_nDistance + _arrGraphEdges[_j]->m_nWeight) < _pNode2->m_nDistance)
{
_pNode2->m_pPreNode = _pNode;
_pNode2->m_nDistance = _pNode->m_nDistance + _arrGraphEdges[_j]->m_nWeight;
}
}
}
bool _bSuccess = true;
for (int _j = 0; _j < _arrGraphEdges.GetSize(); _j++)
{
InnerGraph::EdgeIdentity _nIndentity = _arrGraphEdges[_j]->GetIdentity();
Node* _pNode = nullptr;
m_nNodeMappingTree.Search(_nIndentity.m_nStartKey, _pNode);
if (_pNode->m_pPreNode != nullptr
|| _pNode->m_pGraphNode == _pGraphNode)
{
Node* _pNode2 = nullptr;
m_nNodeMappingTree.Search(_nIndentity.m_nEndKey, _pNode2);
if ((_pNode2->m_pPreNode == nullptr && _pNode2->m_pGraphNode != _pGraphNode)
|| (_pNode->m_nDistance + _arrGraphEdges[_j]->m_nWeight) < _pNode2->m_nDistance)
{
_bSuccess = false;
break;
}
}
}
if (_bSuccess == false)
{
throw "shortest path is not exist";
}
return _arrpNodes;
}
算法目标&算法的性质证明
算法对关联的图的要求:无要求,任意权重图均可。
算法目标:
求图G所有s可达节点p,s~p的一条最短路径。
目标可实现性证明【正确性证明】
算法处理过程:
设图G的节点个数为n,边的个数为m
执行n次循环迭代
每次执行时,对所有边,依次执行边的松弛
正确性证明:
图G如果是无环的,
则,易于知道给定源点s,对于s可达的任一节点p。
s~p,包含s,p在内路径上节点个数<=n。
图G如果是有环的,只要环路权重之和大于0,
则,对于s可达的任一节点p,s~p最短路径,
包含s,p在内路径上节点个数<=n。
图G如果是有环,且环路权重之和小于等于0,
则,对于s可达的任一节点p,s~p最短路径不存在。
综合,
对s的可达节点p,
在s~p最短路径存在的情况下,s~p最短路径上包含s,p下的节点个数<=n
循环不变式:
在执行第k次迭代时,
我们将得到所有最短路径上节点个数为k+1的最短路径信息。
证明:
初始时,
只有s的m_nDistance为0,其余节点皆为无效值。
s~s最短路径节点数为1。循环不变式成立。
第k次循环迭代时,
依据循环不变式,
我们已经得到所有最短路径上节点个数小于等于k的最短路径信息。
对于任意最短路径上节点个数为k+1的最短路径信息。
假设s~q的最短路径中包含节点个数最少的一条最短路径上含k+1个节点。
则,必有s~t->q
必有s~t是一条s~t的最短路径,
且s~t路径上包含k个节点。
由于我们的假设,
我们在本次迭代前已经得到所有最短路径上节点个数为k的最短路径信息。
故,
迭代后,
我们将得到所有剩余节点中,
最短路径上包含k+1个节点的最短路径信息。
得证。