图__最小生成树

图__最小生成树
标签: primkruskal数据结构算法c++
80人阅读 评论(0) 收藏 举报
本文章已收录于:
分类:

图---最小生成树

学习总结:


//---------------------------------------
//-----根据下图----------------------------------------
//--实现普里姆算法(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

//--------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值