算法--指定源点下的最小生成树

指定源点下的最小生成树

性质

算法输入:
图G
指定的源点
输入限制:
图G须为无向连通图
算法目标:
求取一个权重之和最小的边的集合,
通过此边集合,G中任意两个节点均可以相互到达。

接口设计

template<typename Key, typename Value>
class MinGenerateTree
{
public:
	class Node;
	typename typedef DataStruct::GraphStruct::Graph<Key, Value> InnerGraph;
	typename typedef DataStruct::Tree::SortedBalanceBinaryTree<Key, Node*> InnerTree;

	class Tree
	{
	public:
		DataStruct::Array::DynArray<Key> GetKeys()
		{
			return m_arrNodeKeys;
		}

		DataStruct::Array::DynArray<typename InnerGraph::EdgeIdentity> GetEdges()
		{
			return m_arrEdgeKeys;
		}

	private:
		Tree()
		{

		}

		~Tree()
		{

		}

	private:
		DataStruct::Array::DynArray<Key> m_arrNodeKeys;
		DataStruct::Array::DynArray<typename InnerGraph::EdgeIdentity> m_arrEdgeKeys;
		friend class MinGenerateTree;
	};

	class Node
	{
	private:
		Node()
		{
			m_pNode = nullptr;
			m_pTree = nullptr;
		}

		Node(typename InnerGraph::Node* pNode_)
		{
			m_pNode = pNode_;
			m_pTree = nullptr;
		}

		~Node()
		{
		}

		void SetTree(Tree* pTree_)
		{
			m_pTree = pTree_;
		}
	private:
		typename InnerGraph::Node* m_pNode;
		Tree* m_pTree;
		friend class MinGenerateTree;
	};

	MinGenerateTree(const InnerGraph& nGraph_);
	~MinGenerateTree();

	Tree* RunForNoDirectionAndConnectedGraph();
	Tree* RunForNoDirectionAndConnectedGraph(const Key& nSourceKey_);
private:
	MinGenerateTree(const MinGenerateTree&) = default;
	MinGenerateTree& operator=(const MinGenerateTree&) = default;
private:
	const InnerGraph& m_nGraph;
	InnerTree m_nNodeMappingTree;
	DataStruct::Array::DynArray<Tree*> m_arrpTrees;
};

实现

构造

析构

算法实现

template<typename Key, typename Value>
typename MinGenerateTree<Key, Value>::Tree* MinGenerateTree<Key, Value>::RunForNoDirectionAndConnectedGraph(const Key& nSourceKey_)
{
	InnerGraph::Node* _pSourceNode = nullptr;
	_pSourceNode = m_nGraph.SearchNode(nSourceKey_);
	if (_pSourceNode == nullptr)
	{
		throw "source node is not exist";
	}

	for (int _i = 0; _i < m_arrpTrees.GetSize(); _i++)
	{
		delete m_arrpTrees[_i];
		m_arrpTrees[_i] = nullptr;
	}

	m_arrpTrees.DeleteAll();
	DataStruct::Array::DynArray<InnerTree::Pair> _arrPairs = m_nNodeMappingTree.GetArray();
	for (int _i = 0; _i < _arrPairs.GetSize(); _i++)
	{
		_arrPairs[_i].m_nValue->SetTree(nullptr);
		if (_arrPairs[_i].m_nKey == nSourceKey_)
		{
			Tree* _pTree = nullptr;
			try
			{
				_pTree = new Tree();
			}
			catch (...)
			{
				_pTree = nullptr;
				throw "out of memory";
			}

			_pTree->m_arrNodeKeys.Add(_arrPairs[_i].m_nKey);
			_arrPairs[_i].m_nValue->SetTree(_pTree);
			m_arrpTrees.Add(_pTree);
		}
	}

	DataStruct::Array::DynArray<typename InnerGraph::Edge*> _arrEdges = m_nGraph.GetEdgesArray();
	_arrEdges.Sort(
		[](typename InnerGraph::Edge* pEdgeAddrA_, typename InnerGraph::Edge* pEdgeAddrB_)->int
	{
		double _nRet = (pEdgeAddrA_)->m_nWeight - (pEdgeAddrB_)->m_nWeight;
		if (_nRet > 0.0)
		{
			return 1;
		}
		else if (_nRet < 0.0)
		{
			return -1;
		}
		else
		{
			return 0;
		}
	});

	while (true)
	{
		bool _bNeedAgain = false;
		for (int _i = 0; _i < _arrEdges.GetSize(); _i++)
		{
			InnerGraph::Edge* _pEdge = _arrEdges[_i];
			InnerGraph::EdgeIdentity _nIdentity = _pEdge->GetIdentity();
			Node* _pStartNode = nullptr;
			Node* _pEndNode = nullptr;
			m_nNodeMappingTree.Search(_nIdentity.m_nStartKey, _pStartNode);
			if (_pStartNode == nullptr)
			{
				throw "node not exist";
			}

			m_nNodeMappingTree.Search(_nIdentity.m_nEndKey, _pEndNode);
			if (_pEndNode == nullptr)
			{
				throw "node not exist";
			}

			if ((_pStartNode->m_pTree == nullptr
				&& _pEndNode->m_pTree == m_arrpTrees[0]))
			{
				_pStartNode->SetTree(m_arrpTrees[0]);
				m_arrpTrees[0]->m_arrNodeKeys.Add(_nIdentity.m_nStartKey);
				m_arrpTrees[0]->m_arrEdgeKeys.Add(_nIdentity);
				m_arrpTrees[0]->m_arrEdgeKeys.Add(_nIdentity.Reverse());
				_bNeedAgain = true;
			}
			else if ((_pStartNode->m_pTree == m_arrpTrees[0]
				&& _pEndNode->m_pTree == nullptr))
			{
				_pEndNode->SetTree(m_arrpTrees[0]);
				m_arrpTrees[0]->m_arrNodeKeys.Add(_nIdentity.m_nEndKey);
				m_arrpTrees[0]->m_arrEdgeKeys.Add(_nIdentity);
				m_arrpTrees[0]->m_arrEdgeKeys.Add(_nIdentity.Reverse());
				_bNeedAgain = true;
			}
		}

		if (_bNeedAgain == false)
		{
			break;
		}
	}
	
	if (m_arrpTrees[0]->m_arrNodeKeys.GetSize() != m_nGraph.GetNodesArray().GetSize())
	{
		throw "min tree not exist";
	}

	return m_arrpTrees[0];
}

算法目标&正确性证明

循环不变式:
_pTree始终是G的某最小生成树T的一个最小子生成树

初始时,
_pTree仅包含一个节点,不包含边,满足循环不变式

第k次迭代时,
前k-1次迭代后,循环不变式均满足
若edgek,中起始节点s,终止节点e均属于_pTree,本次不处理,循环不变式在迭代后依然成立
若edgek,中起始节点s,终止节点e均不属于_pTree,本次不处理,循环不变式在迭代后依然成立
若edgek,中起始节点s属于_pTree,终止节点e不属于_pTree
采用反证法证明T的边集合中必然包含(s,e)
对于此时_pTree中节点集合任意一点p
T中存在p~e的一条路径
路径上必然存在一个边(x,e) 横跨  {此时_pTree中节点集合},{e}两个节点集合

依据最小生成树性质
_pTree中边集合+(x,e) 是节点集合{此时_pTree中节点集合+e}的一颗最小生成树T'
考虑
_pTree中边集合+edgek,首先是节点集合{此时_pTree中节点集合+e}的一颗生成树T''
又weight(edgek) < weight(x,e),T'是最小生成树,故T''也是最小生成树

故迭代处理后,
得到的_pTree必然是某颗G最小生成树T的一个子生成树
得证

终止:
G是连通图,故终止时,_pTree将是T
原创文章 130 获赞 86 访问量 6万+

猜你喜欢

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