算法--无环图的单源最短路径

无环图的单源最短路径

算法性质

算法对关联的图的要求:无环的权重图。
算法性质:
可求得图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 = 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*> RunForNoCircle(const Key& nSourceKey_);
private:
	ShorestPath(const ShorestPath&) = default;
	ShorestPath& operator=(const ShorestPath&) = default;
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()
{
	DataStruct::Array::DynArray<InnerTree::Pair> _arrTreePairs = m_nNodeMappingTree.GetArray();
	for (int _i = 0; _i < _arrTreePairs.GetSize(); _i++)
	{
		delete (_arrTreePairs[_i].m_nValue);
		_arrTreePairs[_i].m_nValue = nullptr;
	}
}

算法运行

template<typename Key, typename Value>
DataStruct::Array::DynArray<typename ShorestPath<Key, Value>::Node*> ShorestPath<Key, Value>::RunForNoCircle(const Key& nSourceKey_)
{
	InnerGraph::Node* _pSourceNode = m_nGraph.SearchNode(nSourceKey_);
	if (_pSourceNode == 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();
	}

	TopologySort<Key, Value> _alTopologySort(m_nGraph);
	DataStruct::Array::DynArray<typename DepthFirstVisit<Key, Value>::Node*> _arrTempNodes = _alTopologySort.Run();
	DataStruct::Array::DynArray<Key> _arrKeys;
	for (int _i = 0; _i < _arrTempNodes.GetSize(); _i++)
	{
		InnerGraph::Node* _pNode = _arrTempNodes[_i]->GetGraphNode();
		if (_pNode == nullptr)
		{
			throw "graph node not exist";
		}

		_arrKeys.Add(_pNode->GetPair().m_nKey);
	}

	// 对按拓扑排序处理的所有节点
	for (int _i = 0; _i < _arrKeys.GetSize(); _i++)
	{
		int _nKey = _arrKeys[_i];
		Node* _pNode = nullptr;
		m_nNodeMappingTree.Search(_nKey, _pNode);
		if (_pNode == nullptr)
		{
			throw "node not exist";
		}

		InnerGraph::Node* _pGraphNode = _pNode->m_pGraphNode;
		DataStruct::Array::DynArray<Key> _arrDestKeys = _pGraphNode->GetDests();
		// 依次处理每个节点所有可达节点
		for (int _j = 0; _j < _arrDestKeys.GetSize(); _j++)
		{
			if (_pNode->m_pPreNode != nullptr
				|| _pNode->m_pGraphNode == _pSourceNode)
			{
				Node* _pDestNode = nullptr;
				m_nNodeMappingTree.Search(_arrDestKeys[_j], _pDestNode);
				if (_pDestNode == nullptr)
				{
					throw "dest node not exist";
				}

				InnerGraph::EdgeIdentity _nIdentity;
				_nIdentity.m_nStartKey = _pNode->m_pGraphNode->GetPair().m_nKey;
				_nIdentity.m_nEndKey = _pDestNode->m_pGraphNode->GetPair().m_nKey;
				InnerGraph::Edge* _pEdge = nullptr;
				_pEdge = m_nGraph.SearchEdge(_nIdentity);
				if (_pEdge == nullptr)
				{
					throw "edge not exist";
				}

				// 对可达节点进行松弛操作
				if ((_pDestNode->m_pPreNode == nullptr && _pDestNode->m_pGraphNode != _pSourceNode)
					|| (_pDestNode->m_nDistance > _pNode->m_nDistance + _pEdge->m_nWeight))
				{
					_pDestNode->m_pPreNode = _pNode;
					_pDestNode->m_nDistance = _pNode->m_nDistance + _pEdge->m_nWeight;
				}
			}
		}
	}

	return _arrpNodes;
}

算法目标&正确性分析

循环不变式
迭代处理到节点p时,p的s~p的最短路径信息是已知的
初始时,
处理首个节点p0,
1. 若p0不为s,
则,任何其他节点q,不存在q->p0
证明不存在s~p0,采用反证法
假设存在某s~p0,具体为s->x1->...->xk->p0
因为对于任意节点x,不存在x->p0,故假设不成立。
由于不存在s~p0,故p0的最短路径信息是已知的,即默认下的不存在。
2. 若p0为s,则,采用直接证明法
易于知道p0的最短路径信息是已知的。
综合,初始时,循环不变式成立。

迭代处理到节点pk时,证明此时s~pk的最短路径信息是已知的。
依据循环不变式,p0,...,p(k-1)的最短路径信息都是已知的。
1. 假设pk是s可达的。
则对于s~pk的某条最短路径,具体为s->x1->...->xt->pk
证明对于s,x1,...xt中节点必然按s,x1,...xt顺序出现在pk前的主循环的迭代中

首先对于xt,则依据拓扑排序性质,可知xt必然在pk前面
接着对于x(t-1),则依据拓扑排序性质,可知x(t-1)必然在xt前面
...
最后对于s,则依据拓扑排序性质,可知s必然在x1前面

依据最短路径性质
1. 假设存在某最短路径s->x1->....->xn->p
则
s->x1是s~x1最短路径
s->x1->x2是s~x2最短路径
...
s->x1->....->xn是s~xn最短路径
2. 在算法处理中,节点最短路径一旦确定,后续算法运行中将不会再发生变化

由于依据循环不变式,xt的最短路径信息是已经知道的
则,在对xt做所有可达节点松弛操作时,必然会设置pk的最短路径信息
故,pk的最短路径信息是已经存在的。

2. 假设pk是s不可达的
由于不可达,故pk维持默认值
也即s~pk的最短路径信息是已知的

综合,循环不变式成立

算法正确性证明
依据迭代过程的循环不变式,
易于知道,迭代处理后,将知道所有节点p的s~p的最短路径信息
原创文章 134 获赞 87 访问量 6万+

猜你喜欢

转载自blog.csdn.net/x13262608581/article/details/105871942