图__最小生成树

来源:互联网 发布:集体智慧编程 百度云 编辑:程序博客网 时间:2024/04/29 01:28
图__最小生成树
标签: primkruskal数据结构算法c++
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
    原创粉丝点击