美文网首页数据结构与算法C语言C++
数据机构探险之图(下)篇:代码实战

数据机构探险之图(下)篇:代码实战

作者: 天涯明月笙 | 来源:发表于2017-09-12 20:57 被阅读89次

    数据机构探险之图篇(代码编写)

    • 图的存储(邻接矩阵) & 图的深度优先 & 广度优先
    • 图的编码实战-最小生成树(普里姆算法)
    • 图的编码实战-最小生成树之克鲁斯卡尔算法

    图的存储(邻接矩阵) & 图的深度优先 & 广度优先

    要求 题目
    #ifndef NODE_H
    #define NODE_H
    class Node
    {
    public:
        Node(char data = 0);
        char m_cData;//数据值
        bool m_bIsVisited;//有没有被访问
    };
    #endif
    
    #include "Node.h"
    
    Node::Node(char data)
    {
        m_cData = data;
        m_bIsVisited = false;
    }
    
    #ifndef CMAP_H
    #define CMAP_H
    #include "Node.h"
    #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 setValueToMatrixForUndirectedGraph(int row, int col, int val = 1);
    
        void printMatrix();
        //打印邻接矩阵
    
        void depthFirstTraverse(int nodeIndex);//深度优先遍历
        void breadthFirstTraverse(int nodeIndex);//广度优先遍历
    
    private:
        bool getValueFromMatrix(int row, int col, int &val);//从矩阵中获取权值
        void breadthFirstTraverseImpl(vector<int> preVec);//广度优先遍历实现函数
    
    private:
        int m_iCapacity;
        //图中最多可以容纳的顶点数
        int m_iNodeCount;
        //已经添加的顶点(结点)个数
        Node *m_pNodeArray;
        //用来存放顶点数组
        int *m_pMatrix;
        //用来存放邻接矩阵
    };
    
    #endif
    
    

    Cmap.cpp:

    #include "CMap.h"
    #include <iostream>
    #include <vector>
    #include "Node.h"
    using namespace std;
    
    CMap::CMap(int capacity)
    {
        m_iCapacity = capacity;
        m_iNodeCount = 0;
        m_pNodeArray = new Node[m_iCapacity];
        m_pMatrix = new int[m_iCapacity * m_iCapacity];//邻接矩阵size乘size
        //邻接矩阵初始化为全0
        //memset(m_pMatrix, 0, m_iCapacity * m_iCapacity * sizeof(int));
        //将s所指向的某一块内存中的前n个 字节的内容全部设置为ch指定的ASCII值, 第一个值为指定的内存地址,块的大小由第三个参数指定
        for (int i=0;i<m_iCapacity*m_iCapacity;i++)
        {
            m_pMatrix[i] = 0;
        }
    
    }
    
    CMap::~CMap()
    {
        delete []m_pNodeArray;
        delete[]m_pMatrix;
    }
    
    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::setValueToMatrixForUndirectedGraph(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;
    }
    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::printMatrix()
    {
        //两重循环(i行k列)
        for (int i=0;i<m_iCapacity;i++)
        {
            for (int k=0;k<m_iCapacity;k++)
            {
                cout << m_pMatrix[i*m_iCapacity + k] << " ";
            }
            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> curVec;
        curVec.push_back(nodeIndex);
    
        breadthFirstTraverseImpl(curVec);
    
    }
    
    void CMap::breadthFirstTraverseImpl(vector<int> preVec)
    {
        int value = 0;
        vector<int> curVec;
    
        //prevec为上一层节点
        for (int j = 0; j < (int)preVec.size(); j++)
        {
            for (int i=0;i<m_iCapacity;i++)
            {
                getValueFromMatrix(preVec[j], i, value);
                if (value != 0)
                {
                    if (m_pNodeArray[i].m_bIsVisited)
                    {
                        continue;
                    }
                    else
                    {
                        cout << m_pNodeArray[i].m_cData << " ";
                        m_pNodeArray[i].m_bIsVisited = true;
    
                        curVec.push_back(i);
                    }
                }
            }
        }
        if (curVec.size() == 0)
        {
            return;
        }
        else
        {
            breadthFirstTraverseImpl(curVec);
        }
    
    }
    

    main.cpp:

    #include "CMap.h"
    #include <stdlib.h>
    #include "Node.h"
    #include <iostream>
    using namespace std;
    
    int main()
    {
        CMap *pMap = new CMap(8);
    
        Node *pNodeA = new Node('A');
        Node *pNodeB = new Node('B');
        Node *pNodeC = new Node('C');
        Node *pNodeD = new Node('D');
        Node *pNodeE = new Node('E');
        Node *pNodeF = new Node('F');
        Node *pNodeG = new Node('G');
        Node *pNodeH = new Node('H');
    
    
        pMap->addNode(pNodeA);
        pMap->addNode(pNodeB);
        pMap->addNode(pNodeC);
        pMap->addNode(pNodeD);
        pMap->addNode(pNodeE);
        pMap->addNode(pNodeF);
        pMap->addNode(pNodeG);
        pMap->addNode(pNodeH);
    
        pMap->setValueToMatrixForUndirectedGraph(0, 1);
        pMap->setValueToMatrixForUndirectedGraph(0, 3);
        pMap->setValueToMatrixForUndirectedGraph(1, 2);
        pMap->setValueToMatrixForUndirectedGraph(1, 5);
        pMap->setValueToMatrixForUndirectedGraph(3, 6);
        pMap->setValueToMatrixForUndirectedGraph(3, 7);
        pMap->setValueToMatrixForUndirectedGraph(6, 7);
        pMap->setValueToMatrixForUndirectedGraph(2, 4);
        pMap->setValueToMatrixForUndirectedGraph(4, 5);
    
        pMap->printMatrix();
        cout << endl;
    
        pMap->resetNode();
        //指定起始点的索引
        pMap->depthFirstTraverse(0);
        cout << endl;
    
        pMap->resetNode();
        pMap->breadthFirstTraverse(0);
        cout << endl;
    
        system("pause");
        return 0;
    }
    

    运行结果:

    运行结果

    图的编码实战-最小生成树(普里姆算法)

    例子

    边与边之间存在权值。如a-b 为6

    edge.h&cpp:

    #ifndef EDGE_H
    #define EDGE_H
    
    class Edge
    {
    public:
        Edge(int nodeIndexA = 0, int nodeIndexB = 0,int weightValue = 0);
        int m_iNodeIndexA;
        int m_iNodeIndexB;
    
        int m_iWeightValue;
    
        //标记已经挑出来的边
        bool m_bSelected;
    };
    
    #endif
    
    
    #include "Edge.h"
    
    Edge::Edge(int nodeIndexA, int nodeIndexB, int weightValue)
    {
        m_iNodeIndexA = nodeIndexA;
        m_iNodeIndexB = nodeIndexB;
        m_iWeightValue = weightValue;
        m_bSelected = false;
    }
    

    node.h&cpp:

    #ifndef NODE_H
    #define NODE_H
    class Node
    {
    public:
        Node(char data = 0);
        char m_cData;//数据值
        bool m_bIsVisited;//有没有被访问
    };
    #endif
    
    
    #include "Node.h"
    
    Node::Node(char data)
    {
        m_cData = data;
        m_bIsVisited = false;
    }
    

    cmap.h & cpp:

    #ifndef CMAP_H
    #define CMAP_H
    #include "Node.h"
    #include <vector>
    #include "Edge.h"
    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 setValueToMatrixForUndirectedGraph(int row, int col, int val = 1);
    
        void printMatrix();
        //打印邻接矩阵
    
        void depthFirstTraverse(int nodeIndex);//深度优先遍历
        void breadthFirstTraverse(int nodeIndex);//广度优先遍历
        void primTree(int nodeIndex); //普里姆生成树指定的第一个点,找出与他相连的最小边
    private:
        bool getValueFromMatrix(int row, int col, int &val);//从矩阵中获取权值
        void breadthFirstTraverseImpl(vector<int> preVec);//广度优先遍历实现函数
    
    
    
        int getMinEdge(vector<Edge> edgeVec);
    
    
    
    private:
        int m_iCapacity;
        //图中最多可以容纳的顶点数
        int m_iNodeCount;
        //已经添加的顶点(结点)个数
        Node *m_pNodeArray;
        //用来存放顶点数组
        int *m_pMatrix;
        //用来存放邻接矩阵
    
        Edge *m_pEdge;
        
    };
    
    #endif
    
    
    #include "CMap.h"
    #include <iostream>
    #include <vector>
    #include "Node.h"
    using namespace std;
    
    CMap::CMap(int capacity)
    {
        m_iCapacity = capacity;
        m_iNodeCount = 0;
        m_pNodeArray = new Node[m_iCapacity];
        m_pMatrix = new int[m_iCapacity * m_iCapacity];//邻接矩阵size乘size
        //邻接矩阵初始化为全0
        //memset(m_pMatrix, 0, m_iCapacity * m_iCapacity * sizeof(int));
        //将s所指向的某一块内存中的前n个 字节的内容全部设置为ch指定的ASCII值, 第一个值为指定的内存地址,块的大小由第三个参数指定
        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;
    }
    
    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::setValueToMatrixForUndirectedGraph(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;
    }
    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::printMatrix()
    {
        //两重循环(i行k列)
        for (int i=0;i<m_iCapacity;i++)
        {
            for (int k=0;k<m_iCapacity;k++)
            {
                cout << m_pMatrix[i*m_iCapacity + k] << " ";
            }
            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> curVec;
        curVec.push_back(nodeIndex);
    
        breadthFirstTraverseImpl(curVec);
    
    }
    
    void CMap::breadthFirstTraverseImpl(vector<int> preVec)
    {
        int value = 0;
        vector<int> curVec;
    
        //prevec为上一层节点
        for (int j = 0; j < (int)preVec.size(); j++)
        {
            for (int i=0;i<m_iCapacity;i++)
            {
                getValueFromMatrix(preVec[j], i, value);
                if (value != 0)
                {
                    if (m_pNodeArray[i].m_bIsVisited)
                    {
                        continue;
                    }
                    else
                    {
                        cout << m_pNodeArray[i].m_cData << " ";
                        m_pNodeArray[i].m_bIsVisited = true;
    
                        curVec.push_back(i);
                    }
                }
            }
        }
        if (curVec.size() == 0)
        {
            return;
        }
        else
        {
            breadthFirstTraverseImpl(curVec);
        }
    
    }
    
    //普利姆生成树
    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;
        //什么时候停下来,边数等于点数-1时
        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);
                        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;
        }
    }
    
    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 (minWeight == 0)
        {
            return -1;
        }
    
        for ( ;i<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;
    }
    

    main.cpp:

    #include "CMap.h"
    #include <stdlib.h>
    #include "Node.h"
    #include <iostream>
    using namespace std;
    
    int main()
    {
        CMap *pMap = new CMap(6);
    
        Node *pNodeA = new Node('A');
        Node *pNodeB = new Node('B');
        Node *pNodeC = new Node('C');
        Node *pNodeD = new Node('D');
        Node *pNodeE = new Node('E');
        Node *pNodeF = new Node('F');
    
        pMap->addNode(pNodeA);
        pMap->addNode(pNodeB);
        pMap->addNode(pNodeC);
        pMap->addNode(pNodeD);
        pMap->addNode(pNodeE);
        pMap->addNode(pNodeF);
    
        pMap->setValueToMatrixForUndirectedGraph(0,1,6);
        pMap->setValueToMatrixForUndirectedGraph(0,4,5);
        pMap->setValueToMatrixForUndirectedGraph(0,5,1);
        pMap->setValueToMatrixForUndirectedGraph(1,2,3);
        pMap->setValueToMatrixForUndirectedGraph(1,5,2);
        pMap->setValueToMatrixForUndirectedGraph(2,5,8);
        pMap->setValueToMatrixForUndirectedGraph(2,3,7);
        pMap->setValueToMatrixForUndirectedGraph(3,5,4);
        pMap->setValueToMatrixForUndirectedGraph(3,4,2);
        pMap->setValueToMatrixForUndirectedGraph(4,5,9);
    
    
        pMap->primTree(0);
    
        system("pause");
        return 0;
    }
    

    运行结果:

    运行结果

    图的编码实战-最小生成树之克鲁斯卡尔算法

    题目
    • 找出所有的边
    • 在边中找到最小生成树的集合

    node.cpp&h edge.cpp&h与上面的一样

    cmap.h&cpp

    #ifndef CMAP_H
    #define CMAP_H
    #include "Node.h"
    #include <vector>
    #include "Edge.h"
    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 setValueToMatrixForUndirectedGraph(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);//广度优先遍历实现函数
        bool isInSet(vector<int> nodeSet, int target); //判断顶点是否在点集合中
        void mergeNodeSet(vector<int> &nodeSetA, vector<int> nodeSetB);//合并两个点集合
    
    
        int getMinEdge(vector<Edge> edgeVec);
    
    
    
    private:
        int m_iCapacity;
        //图中最多可以容纳的顶点数
        int m_iNodeCount;
        //已经添加的顶点(结点)个数
        Node *m_pNodeArray;
        //用来存放顶点数组
        int *m_pMatrix;
        //用来存放邻接矩阵
    
        Edge *m_pEdge;
        
    };
    
    #endif
    
    #include "CMap.h"
    #include <iostream>
    #include <vector>
    #include "Node.h"
    using namespace std;
    
    CMap::CMap(int capacity)
    {
        m_iCapacity = capacity;
        m_iNodeCount = 0;
        m_pNodeArray = new Node[m_iCapacity];
        m_pMatrix = new int[m_iCapacity * m_iCapacity];//邻接矩阵size乘size
        //邻接矩阵初始化为全0
        //memset(m_pMatrix, 0, m_iCapacity * m_iCapacity * sizeof(int));
        //将s所指向的某一块内存中的前n个 字节的内容全部设置为ch指定的ASCII值, 第一个值为指定的内存地址,块的大小由第三个参数指定
        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::setValueToMatrixForUndirectedGraph(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;
    }
    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::printMatrix()
    {
        //两重循环(i行k列)
        for (int i=0;i<m_iCapacity;i++)
        {
            for (int k=0;k<m_iCapacity;k++)
            {
                cout << m_pMatrix[i*m_iCapacity + k] << " ";
            }
            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> curVec;
        curVec.push_back(nodeIndex);
    
        breadthFirstTraverseImpl(curVec);
    
    }
    
    void CMap::breadthFirstTraverseImpl(vector<int> preVec)
    {
        int value = 0;
        vector<int> curVec;
    
        //prevec为上一层节点
        for (int j = 0; j < (int)preVec.size(); j++)
        {
            for (int i=0;i<m_iCapacity;i++)
            {
                getValueFromMatrix(preVec[j], i, value);
                if (value != 0)
                {
                    if (m_pNodeArray[i].m_bIsVisited)
                    {
                        continue;
                    }
                    else
                    {
                        cout << m_pNodeArray[i].m_cData << " ";
                        m_pNodeArray[i].m_bIsVisited = true;
    
                        curVec.push_back(i);
                    }
                }
            }
        }
        if (curVec.size() == 0)
        {
            return;
        }
        else
        {
            breadthFirstTraverseImpl(curVec);
        }
    
    }
    
    //普利姆生成树
    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;
        //什么时候停下来,边数等于点数-1时
        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);
                        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;
        }
    }
    
    int CMap::getMinEdge(vector<Edge> edgeVec)
    {
        //找到第一条边而且是没有被选出去的边
        int minWeight = 0;
        int edgeIndex = 0;
        int i = 0;
        for ( ;i<(int)edgeVec.size();i++)
        {
            if (!edgeVec[i].m_bSelected)
            {
                //该边还没有被选过
                minWeight = edgeVec[i].m_iWeightValue;
                edgeIndex = i;
                break;//找到第一条边迅速跳出循环
            }
        }
    
        if (minWeight == 0)
        {
            return -1;
        }
    
        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;
    }
    
    //克鲁斯卡尔算法生成树
    void CMap::kruskalTree()
    {
        int value = 0;//用来取权值的
    
        int edgeCount = 0;
        //定义存放结点集合的数组
        vector<vector<int>>  nodeSets;
        //点的集合不止一个
    
        //第一步取出所有边
        vector<Edge> edgeVec;
        for (int i=0;i<m_iCapacity;i++)
        {
            for (int k=i+1;k<m_iCapacity;k++)
            {
                //取出上半个三角的值
                getValueFromMatrix(i, k, value);
                if (value!=0)
                {
                    Edge edge(i, k, value);
                    edgeVec.push_back(edge);
    
    
                }
            }
        }
    
        //第二步:从所有边中取出最小生成树的边
        //1. 找到算法的结束条件(边数等于顶点数-1)
        while (edgeCount <m_iCapacity-1)
        {
            //2. 从边集合中找到最小边(最小边的点)
            int minEdgeIndex = getMinEdge(edgeVec);
            edgeVec[minEdgeIndex].m_bSelected = true;
            //3. 找出最小边连接的点
            int nodeAIndex = edgeVec[minEdgeIndex].m_iNodeIndexA;
            int nodeBIndex = edgeVec[minEdgeIndex].m_iNodeIndexB;
    
            bool nodeAIsInSet = false;
            bool nodeBIsInSet = false;
    
            int nodeAInSetLabel = -1;
            int nodeBInSetLabel = -1;
    
            //4. 找出点所在的点集合
            for (int i = 0; i <(int)nodeSets.size(); i++)
            {
                nodeAIsInSet = isInSet(nodeSets[i],nodeAIndex);
                if (nodeAIsInSet)
                {
                    //保存i的值
                    nodeAInSetLabel = i;
                }
            }
            for (int i = 0; i < (int)nodeSets.size(); i++)
            {
                nodeBIsInSet = isInSet(nodeSets[i], nodeBIndex);
                if (nodeBIsInSet)
                {
                    //保存i的值
                    nodeBInSetLabel = i;
                }
            }
            //5. 根据点所在集合的不同做出不同处理
            if (nodeAInSetLabel == -1 && nodeBInSetLabel == -1)
            {
                vector<int> vec;
                vec.push_back(nodeAIndex);
                vec.push_back(nodeBIndex);
    
                nodeSets.push_back(vec);
            }
    
            else if (nodeAInSetLabel == -1 && nodeBInSetLabel !=-1)
            {
                //此时a不在任何一个集合中。而nodeB已经在某一集合中
                //因为nodea&b为一边的两点。所有将a也加入b的集合
                nodeSets[nodeBInSetLabel].push_back(nodeAIndex);
            }
            else if (nodeAInSetLabel != -1 && nodeBInSetLabel == -1)
            {
                //此时b不在任何一个集合中。而nodeA已经在某一集合中
                //因为nodea&b为一边的两点。所有将b也加入a的集合
                nodeSets[nodeAInSetLabel].push_back(nodeBIndex);
            }
            else if (nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel != nodeBInSetLabel)
            {
                //两者在两个不同的集合中,将集合合并
                mergeNodeSet(nodeSets[nodeAInSetLabel], nodeSets[nodeBInSetLabel]);
    
                for (int k = nodeBInSetLabel;k<(int)nodeSets.size()-1;k++)
                {
                    //相当于删除了一个节点后面的都向前挪一位
                    nodeSets[k] = nodeSets[k + 1];
    
                }
    
            }
            else if(nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel == nodeBInSetLabel)
            {
                //两个都不等于-1.相等还在同一个集合中。
                continue;
            }
    
            m_pEdge[edgeCount] = edgeVec[minEdgeIndex];
            edgeCount++;
    
    
            cout << edgeVec[minEdgeIndex].m_iNodeIndexA << "---" << edgeVec[minEdgeIndex].m_iNodeIndexB << "  ";
            cout << edgeVec[minEdgeIndex].m_iWeightValue << endl;
        }
        
    
    }
    
    bool CMap::isInSet(vector<int> nodeSet, int target)
    {
        //参数一点的集合。参数二点的索引
        for (int i=0;i<(int)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<(int)nodeSetB.size();i++)
        {
            //合并就是将b的点依次加到a的后面
            nodeSetA.push_back(nodeSetB[i]);
        }
    }
    

    main.cpp:

    #include "CMap.h"
    #include <stdlib.h>
    #include "Node.h"
    #include <iostream>
    using namespace std;
    
    int main()
    {
        CMap *pMap = new CMap(6);
    
        Node *pNodeA = new Node('A');
        Node *pNodeB = new Node('B');
        Node *pNodeC = new Node('C');
        Node *pNodeD = new Node('D');
        Node *pNodeE = new Node('E');
        Node *pNodeF = new Node('F');
    
        pMap->addNode(pNodeA);
        pMap->addNode(pNodeB);
        pMap->addNode(pNodeC);
        pMap->addNode(pNodeD);
        pMap->addNode(pNodeE);
        pMap->addNode(pNodeF);
    
        pMap->setValueToMatrixForUndirectedGraph(0,1,6);
        pMap->setValueToMatrixForUndirectedGraph(0,4,5);
        pMap->setValueToMatrixForUndirectedGraph(0,5,1);
        pMap->setValueToMatrixForUndirectedGraph(1,2,3);
        pMap->setValueToMatrixForUndirectedGraph(1,5,2);
        pMap->setValueToMatrixForUndirectedGraph(2,5,8);
        pMap->setValueToMatrixForUndirectedGraph(2,3,7);
        pMap->setValueToMatrixForUndirectedGraph(3,5,4);
        pMap->setValueToMatrixForUndirectedGraph(3,4,2);
        pMap->setValueToMatrixForUndirectedGraph(4,5,9);
    
    
        //pMap->primTree(0);
        pMap->kruskalTree();
        system("pause");
        return 0;
    }
    

    运行结果:

    运行结果

    相关文章

      网友评论

        本文标题:数据机构探险之图(下)篇:代码实战

        本文链接:https://www.haomeiwen.com/subject/zwdhsxtx.html