算法--無環圖的單源最短路徑

無環圖的單源最短路徑

算法性質

算法對關聯的圖的要求:無環的權重圖。
算法性質:
可求得圖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的最短路徑信息
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章