ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2020-05-03 12:40:32  阅读:263  来源: 互联网

标签:MinGenerateTree Tree 源点 nullptr 最小 节点 算法 arrpTrees pTree


指定源点下的最小生成树

性质

算法输入:
图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

标签:MinGenerateTree,Tree,源点,nullptr,最小,节点,算法,arrpTrees,pTree
来源: https://blog.csdn.net/x13262608581/article/details/105879784

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有