图__最小生成树
来源:互联网 发布:集体智慧编程 百度云 编辑:程序博客网 时间:2024/04/29 01:28
图__最小生成树
//---------------------------------------
//-----根据下图----------------------------------------
//--实现普里姆算法(Prim)--及--克鲁斯卡尔算法(kruskal)---------------
/*
A
/ | \
B -- F -- E
\ / \ /
C -- D
A B C D E F
索引: 0 1 2 3 4 5
权值:A-B 6 A-F 1 A-E 5
B-C 3 B-F 2
C-F 8 C-D 7
D-F 4 D-E 2
E-F 9
//无向图
A B C D E
A 0 1 1 0 0
B 1 0 0 1 1
C 1 0 0 0 0
D 0 1 0 0 0
E 0 1 0 0 0
*/
Node.h
Node.cpp
Edge.h
Edge.cpp
CMap.h
CMap.cpp
demo.cpp
标签: primkruskal数据结构算法c++
2016-09-12 09:52 80人阅读 评论(0)收藏举报
本文章已收录于:
分类:
作者同类文章X
版权声明:本文为博主原创文章,未经博主允许不得转载。
图---最小生成树
学习总结:
//---------------------------------------
//-----根据下图----------------------------------------
//--实现普里姆算法(Prim)--及--克鲁斯卡尔算法(kruskal)---------------
/*
A
/ | \
B -- F -- E
\ / \ /
C -- D
A B C D E F
索引: 0 1 2 3 4 5
权值:A-B 6 A-F 1 A-E 5
B-C 3 B-F 2
C-F 8 C-D 7
D-F 4 D-E 2
E-F 9
//无向图
A B C D E
A 0 1 1 0 0
B 1 0 0 1 1
C 1 0 0 0 0
D 0 1 0 0 0
E 0 1 0 0 0
*/
Node.h
#ifndef NODE_H#define NODE_H//-----------------//-----顶点----------class Node{public: Node(char data = 0); char m_cData; bool m_bIsVisited; };#endif
Node.cpp
#include"Node.h"#include<iostream>#include<stdio.h>using namespace std;Node::Node(char data){ m_cData = data; m_bIsVisited = false;}
Edge.h
#ifndef EDGE_H#define EDGE_H//-------------------//----边-------------class Edge{public: Edge(int nodeIndexA = 0, int nodeIndexB = 0, int weightValue = 0);public: int m_iNodeIndexA;//A索引 int m_iNodeIndexB;//B索引 int m_iWeightValue;//权值 bool m_bSelected; };#endif
Edge.cpp
#include"Edge.h"Edge::Edge(int nodeIndexA, int nodeIndexB, int weightValue){ m_iNodeIndexA = nodeIndexA; m_iNodeIndexB = nodeIndexB; m_iWeightValue = weightValue; m_bSelected = false;}
CMap.h
#ifndef CMAP_H#define CMAP_H#include"Node.h"#include"Edge.h"#include<iostream>#include<vector>using namespace std;//---------------------------//--------图--------------------class CMap{ public: CMap(int capacity); ~CMap(); bool addNode(Node *pNode);//添加顶点(节点) void resetNode(); //重置顶点 bool setValueToMatrixForDirectedGraph(int row, int col, int val = 1);//为有向图设置邻接矩阵 bool setValueToMatrixForUndriectedGraph(int row, int col, int val = 1);//为无向图设置邻接矩阵 void printMatrix();//打印邻接矩阵 void depthFirstTraverse(int nodeIndex);//深度优先遍历 void breadthFirstTraverse(int nodeIndex);//广度优先遍历 void primTree(int nodeIndex);//普里姆算法最小生成树 void kruskalTree(); //克鲁斯卡尔算法最小生成树 private: bool getValueFromMatrix(int row, int col, int &val);//从矩阵中获取权值 void breadthFirstTraverseImpl(vector<int> preVec);//广度优先遍历实现函数 int getMinEdge(vector<Edge> edgeVec);//获得最小边 bool isInSet(vector<int> nodeSet, int target);//判断顶点(节点)是否在集合中 void mergeNodeSet(vector<int> &nodeSetA, vector<int> nodeSetB);//合并两个点的集合,B合并到A中private: int m_iCapacity;//容量 int m_iNodeCount;//节点个数 Node *m_pNodeArray;//顶点数组 int *m_pMatrix;//存放邻接矩阵,弧 Edge *m_pEdge;//边的集合};#endif
CMap.cpp
#include"CMap.h"CMap::CMap(int capacity){ m_iCapacity = capacity; m_iNodeCount = 0; m_pNodeArray = new Node[m_iCapacity]; m_pMatrix = new int[m_iCapacity*m_iCapacity]; //memset(m_pMatrix, 0, m_iCapacity*m_iCapacity*sizeof(int));//内存的设定 //或 for(int i = 0; i < m_iCapacity*m_iCapacity; i++){ m_pMatrix[i] = 0; } m_pEdge = new Edge[m_iCapacity-1];//边的集合 }CMap::~CMap(){ delete []m_pNodeArray; delete []m_pMatrix; delete []m_pEdge;}bool CMap::addNode(Node *pNode){ if(pNode == NULL){ return false; } m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData; m_iNodeCount++; return true;}void CMap::resetNode(){ for(int i = 0; i < m_iNodeCount; i++){ m_pNodeArray[i].m_bIsVisited = false; }}bool CMap::setValueToMatrixForDirectedGraph(int row, int col, int val){ if(row < 0 || row >= m_iCapacity){ return false; } if(col < 0 || col >= m_iCapacity){ return false; } m_pMatrix[row*m_iCapacity + col] = val; return true;}bool CMap::setValueToMatrixForUndriectedGraph(int row, int col, int val){ if(row < 0 || row >= m_iCapacity){ return false; } if(col < 0 || col >= m_iCapacity){ return false; } m_pMatrix[row*m_iCapacity + col] = val; m_pMatrix[col*m_iCapacity + row] = val; return true;}void CMap::printMatrix(){ for(int i = 0; i < m_iCapacity; i++){ for(int j = 0; j < m_iCapacity; j++){ cout << m_pMatrix[i*m_iCapacity + j] << " "; } cout << endl; }}void CMap::depthFirstTraverse(int nodeIndex){//深度优先搜索 int value = 0; cout << m_pNodeArray[nodeIndex].m_cData << " "; m_pNodeArray[nodeIndex].m_bIsVisited = true; //通过邻接矩阵判断是否与其他的顶点有连接,看是否存在一条连通的弧 for(int i = 0; i < m_iCapacity; i++){ getValueFromMatrix(nodeIndex, i, value);//取出相应的弧 //判断有弧连接其他顶点 if(value != 0){//有这样的弧 //判断 连接的顶点 是否被访问过 if(m_pNodeArray[i].m_bIsVisited){ continue; } else{//没有访问过,则递归访问 depthFirstTraverse(i); } } else{ continue; } }}void CMap::breadthFirstTraverse(int nodeIndex){//广度优先遍历 cout << m_pNodeArray[nodeIndex].m_cData << " "; m_pNodeArray[nodeIndex].m_bIsVisited = true; vector<int> cur; cur.push_back(nodeIndex);//保存顶点的索引 breadthFirstTraverseImpl(cur);//实现广度优先遍历的函数}//普里姆算法最小生成树void CMap::primTree(int nodeIndex){ int value = 0;//保存权值 int edgeCount = 0;//边的计数器 vector<int> nodeVec;//存储点的集合,用索引代替 vector<Edge> edgeVec;//边的集合 cout << m_pNodeArray[nodeIndex].m_cData << endl; nodeVec.push_back(nodeIndex); m_pNodeArray[nodeIndex].m_bIsVisited = true; while(edgeCount < m_iCapacity - 1){ int temp = nodeVec.back(); //放入待选边的集合 for(int i = 0; i < m_iCapacity; i++){ //寻找待选边的集合 getValueFromMatrix(temp, i, value);//从邻接矩阵中获取权值 if(value != 0){ if(m_pNodeArray[i].m_bIsVisited){ continue; } else{ Edge edge(temp, i, value);//确定了nodeIndexA,nodeIndexB等索引 edgeVec.push_back(edge);//不会放重复的边 } } } //从待选边中选出最小的边 int edgeIndex = getMinEdge(edgeVec);//返回最小边的索引 edgeVec[edgeIndex].m_bSelected = true; cout << edgeVec[edgeIndex].m_iNodeIndexA << "-->" << edgeVec[edgeIndex].m_iNodeIndexB << " "; cout << edgeVec[edgeIndex].m_iWeightValue << endl; //放入最小生成树边的集合中 m_pEdge[edgeCount] = edgeVec[edgeIndex]; edgeCount++; //最小边连接的点 int nextNodeIndex = edgeVec[edgeIndex].m_iNodeIndexB; //将下一个点放入点的集合 nodeVec.push_back(nextNodeIndex); m_pNodeArray[nextNodeIndex].m_bIsVisited = true; cout << m_pNodeArray[nextNodeIndex].m_cData << endl; } }//克鲁斯卡尔算法最小生成树void CMap::kruskalTree(){ int value = 0;//存放权值 int edgeCount = 0;//边计数器 //定义存放节点 集合 的数组,可能不止一个点的集合,demo.cpp运行结果就是如此 vector<vector<int> > nodeSets; //<1>取出所有边 vector<Edge> edgeVec; for(int i = 0; i < m_iCapacity; i++){ for(int j = i + 1; j < m_iCapacity; j++){//上三角,不包含主对角线,例如A-A,B-B..没意义 getValueFromMatrix(i, j, value);//从邻接矩阵中获取权值 if(value != 0){ Edge edge(i, j, value);//确定了nodeIndexA,nodeIndexB等索引 edgeVec.push_back(edge);//放入边集合中 } } } //<2>从所有边中取出组成最小生成树的边 //1.算法结束条件 while(edgeCount < m_iCapacity - 1){ //2.从边集合中找到最小边 int minEdgeIndex = getMinEdge(edgeVec); edgeVec[minEdgeIndex].m_bSelected = true; //3.找出最小边连接的点 int nodeIndexA = edgeVec[minEdgeIndex].m_iNodeIndexA; int nodeIndexB = edgeVec[minEdgeIndex].m_iNodeIndexB; //4.找出点所在的集合 bool nodeAIsInSet = false; bool nodeBIsInSet = false; int nodeAInSetLabel = -1; int nodeBInSetLabel = -1; for(int i = 0; i < nodeSets.size(); i++){//A点集合所在的索引 nodeAIsInSet = isInSet(nodeSets[i], nodeIndexA); if(nodeAIsInSet){ nodeAInSetLabel = i; } } for(int i = 0; i < nodeSets.size(); i++){//B点集合所在的索引 nodeBIsInSet = isInSet(nodeSets[i], nodeIndexB); if(nodeAIsInSet){ nodeBInSetLabel = i; } } //5.根据点所在集合的不同做不同的处理 if(nodeAInSetLabel == -1 && nodeBInSetLabel == -1){ vector<int> vec; vec.push_back(nodeAInSetLabel); vec.push_back(nodeBInSetLabel); nodeSets.push_back(vec); } else if(nodeAInSetLabel == -1 && nodeBInSetLabel != -1){ nodeSets[nodeBInSetLabel].push_back(nodeIndexA);//nodeIndexA到B集合 } else if(nodeAInSetLabel != -1 && nodeBInSetLabel == -1){ nodeSets[nodeAInSetLabel].push_back(nodeIndexB);//nodeIndexB到A集合 } //合并两个集合 else if(nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel != nodeBInSetLabel){ mergeNodeSet(nodeSets[nodeAInSetLabel], nodeSets[nodeBInSetLabel]);//合并到A集合 for(int k = nodeBInSetLabel; k < (int)nodeSets.size(); k++){ nodeSets[k] = nodeSets[k+1];//清除B集合所占空间 } } //两个点在一个集合中形成了回路,舍弃 else if(nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel == nodeBInSetLabel){ continue; } m_pEdge[edgeCount] = edgeVec[minEdgeIndex];//放入边的集合中 edgeCount++;//边数增加 cout << edgeVec[minEdgeIndex].m_iNodeIndexA << "-->" << edgeVec[minEdgeIndex].m_iNodeIndexB << " "; cout << edgeVec[minEdgeIndex].m_iWeightValue << endl; } }bool CMap::getValueFromMatrix(int row, int col, int &val){ if(row < 0 || row >= m_iCapacity){ return false; } if(col < 0 || col >= m_iCapacity){ return false; } val = m_pMatrix[row*m_iCapacity + col]; return true;}void CMap::breadthFirstTraverseImpl(vector<int> preVec){ int value = 0; vector<int> cur; for(int i = 0; i < preVec.size();i++){//上一层的节点数 for(int j = 0; j < m_iCapacity; j++){ //判断当前点与其他点是否有连接 getValueFromMatrix(preVec[i], j, value);//上一个点判断是否有连接j的弧 if(value != 0){ if(m_pNodeArray[j].m_bIsVisited){//看是否被访问过 continue; } else{//若没有访问过的话 cout << m_pNodeArray[j].m_cData << " ";//现有的顶点 m_pNodeArray[j].m_bIsVisited = true; cur.push_back(j);//当前的点保存到数组中 } } } } if(cur.size() == 0){//下一层节点数的判断 return ; } else{//下一层节点数的开始,递归进行深度优先遍历 breadthFirstTraverseImpl(cur); }}int CMap::getMinEdge(vector<Edge> edgeVec){//获得最小边 int minWeight = 0; int edgeIndex = 0; int i = 0; for(; i < edgeVec.size(); i++){//找出第一条没有被访问过的边 if(!edgeVec[i].m_bSelected){ minWeight = edgeVec[i].m_iWeightValue;//权值 edgeIndex = i;//边的索引 break;//找到,则跳出循环 } } if(0 == minWeight){//若都被访问过的话 return -1; } //接着i后面继续找 for(; i < (int)edgeVec.size(); i++){//找出最小权值的边 if(edgeVec[i].m_bSelected){ continue; } else{ if(minWeight > edgeVec[i].m_iWeightValue){ minWeight = edgeVec[i].m_iWeightValue; edgeIndex = i; } } } return edgeIndex;}bool CMap::isInSet(vector<int> nodeSet, int target){ for(int i = 0; i < nodeSet.size(); i++){ if(nodeSet[i] == target){ return true; } } return false;}void CMap::mergeNodeSet(vector<int> &nodeSetA, vector<int> nodeSetB){ for(int i = 0; i < nodeSetB.size(); i++){ nodeSetA.push_back(nodeSetB[i]); }}
demo.cpp
#include"CMap.h"#include<iostream>using namespace std;//---------------------------------------//-----根据下图----------------------------------------//--实现普里姆算法(Prim)--及--克鲁斯卡尔算法(kruskal)---------------/* A / | \ B -- F -- E \ / \ / C -- D A B C D E F索引: 0 1 2 3 4 5权值: A-B 6 A-F 1 A-E 5 B-C 3 B-F 2 C-F 8 C-D 7 D-F 4 D-E 2 E-F 9 //无向图 A B C D E A 0 1 1 0 0 B 1 0 0 1 1 C 1 0 0 0 0 D 0 1 0 0 0 E 0 1 0 0 0*/int main(){ Node *node = new Node[6]; node[0].m_cData = 'A'; node[1].m_cData = 'B'; node[2].m_cData = 'C'; node[3].m_cData = 'D'; node[4].m_cData = 'E'; node[5].m_cData = 'F'; CMap *cmap = new CMap(6); cmap->addNode(&node[0]); cmap->addNode(&node[1]); cmap->addNode(&node[2]); cmap->addNode(&node[3]); cmap->addNode(&node[4]); cmap->addNode(&node[5]); //为无向图设置邻接矩阵 cmap->setValueToMatrixForUndriectedGraph(0, 1, 6); cmap->setValueToMatrixForUndriectedGraph(0, 4, 5); cmap->setValueToMatrixForUndriectedGraph(0, 5, 1); cmap->setValueToMatrixForUndriectedGraph(1, 2, 3); cmap->setValueToMatrixForUndriectedGraph(1, 5, 2); cmap->setValueToMatrixForUndriectedGraph(2, 5, 8); cmap->setValueToMatrixForUndriectedGraph(2, 3, 7); cmap->setValueToMatrixForUndriectedGraph(3, 5, 4); cmap->setValueToMatrixForUndriectedGraph(3, 4, 2); cmap->setValueToMatrixForUndriectedGraph(4, 5, 9); cmap->primTree(0); cout << endl << endl; cmap->kruskalTree(); /*cmap->printMatrix(); cout << endl; cmap->depthFirstTraverse(0); cmap->resetNode(); cout << endl; cmap->breadthFirstTraverse(0);*/ delete cmap; cmap = NULL;}
//控制台运行得:
A
0-->5 1
F
5-->1 2
B
1-->2 3
C
5-->3 4
D
3-->4 2
E
0-->5 1
1-->5 2
3-->4 2
1-->2 3
3-->5 4
//--------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
0 0
- 图__最小生成树
- 图__最小生成树
- POJ 2485(建高速公路__最小生成树)
- 最小生成树 图
- 图 - 生成树和最小生成树 - 最小生成树
- 最小生成树 最小树形图
- 【vijos】【生成树】最小生成树的最小完全图
- 图--生成树和最小生成树
- 图---生成树与最小生成树
- 数据结构 图 最小生成树
- 图的最小生成树
- 图算法--最小生成树
- 图(四)最小生成树
- 图的最小生成树
- 图的最小生成树
- 【图】最小生成树kruskal
- 图的最小生成树
- 图的最小生成树
- 使用gensim和sklearn搭建一个文本分类器(二):代码和注释
- js 面试的坑(三)
- 第三周项目1---顺序表的基本运算
- 前端显示等一系列问题
- 解决aapt "finished with non-zero exit value 1"问题
- 图__最小生成树
- ambari环境搭建记录要点
- C++类和对象的概念
- CentOS 7下LAMP源码安装(2)设置及源码下载
- Monitor IO for Windows
- cv-拉普拉斯算子锐化浅析
- java中非常重要的修饰词---static、this、final、super
- Oracle百万记录sql语句优化技巧
- 并发请求