C++图的操作

来源:互联网 发布:还珠之我是知画 编辑:程序博客网 时间:2024/06/05 17:05

经过漫长的学习,终于对图的结构、表示和遍历及其最小生成树等一系列图相关的操作有了一些理解,因此现在写这篇博客,希望会对大家有用,我们的图是通过邻接矩阵实现的。

Node.h

#ifndef NODE_H#define NODE_Hclass Node{public:    Node(char data = 0);    char m_data;    bool m_isVisited;};#endif

Edge.h

#ifndef EDGE_H#define EDGE_Hclass Edge{public:    Edge(int nodeIndexA = 0, int nodexIndexB = 0, int weightValue = 0);    int m_nodeIndexA;    int m_nodeIndexB;    int m_weightValue;    bool m_selected;};#endif

CMap.h

#ifndef CMAP_H#define CMAP_H#include <vector>#include "Node.h"#include "Edge.h"using namespace std;class CMap{public:    CMap(int capacity);    ~CMap();    bool addNode(Node* node);    void resetNode();    bool setValueToMatrixForDirectedGraph(int row, int col, int value = 1);//为有向图设置邻接矩阵    bool setValueToMatrixForUndirectedGraph(int row, int col, int value = 1);//为无向图设置邻接矩阵    void printMatrix();//打印邻接矩阵    //遍历    void depthFirstTraverse(int nodeIndex);    void breadthFirstTraverse(int nodeIndex);    void depthFirstTraverse_self(int nodeIndex);    void primTree(int nodeIndex);//最小生成树    void kruskalTree();private:    int m_capacity;//图中最多容纳的顶点数    int m_iNodeCount;//已经添加的顶点的数目    Node* m_pNodeArray;//存放顶点数组    int* m_pMatrix;//存放二维数组矩阵,用来表示顶点之间的边的关系    bool getValueFromMatrix(int row, int col, int& val);//从矩阵中获取权值    int getMinEdge(vector<Edge> edgeVec);    void mergeNodeSet(vector<int> &nodeSetA,vector<int> nodeSetB);    bool isInset(vector<int> nodeSet,int target);    //申明一个边的集合用来保存最小生成树的边    Edge* m_edge;};#endif

Node.cpp

#include <iostream>#include "Node.h"using namespace std;Node::Node(char data){    m_data = data;    m_isVisited = false;}

Edge.cpp

#include "Edge.h"Edge::Edge(int nodeIndexA, int nodeIndexB, int weightValue){    m_nodeIndexA = nodeIndexA;    m_nodeIndexB = nodeIndexB;    m_weightValue = weightValue;    m_selected = false;}

CMap.cpp

#include <iostream>#include "CMap.h"#include <queue>using namespace std;CMap::CMap(int capacity){    m_capacity = capacity;    m_iNodeCount = 0;    m_pNodeArray = new Node[m_capacity];    m_pMatrix = new int[m_capacity*m_capacity];    memset(m_pMatrix, 0, m_capacity*m_capacity*sizeof(int));    //生成最小生成树的边    m_edge = new Edge[m_capacity - 1];}CMap::~CMap(){    delete[] m_pNodeArray;    delete[] m_pMatrix;    delete[] m_edge;}bool CMap::addNode(Node* node){    m_pNodeArray[m_iNodeCount].m_data = node->m_data;    m_iNodeCount++;    return true;}void CMap::resetNode(){    for (int i = 0; i < m_iNodeCount; i++){        m_pNodeArray[i].m_isVisited = false;    }}bool CMap::setValueToMatrixForDirectedGraph(int row, int col, int value){    if (row < 0 && row >= m_capacity) return false;    if (col < 0 && col >= m_capacity) return false;    m_pMatrix[row*m_capacity + col] = value;    return true;}bool CMap::setValueToMatrixForUndirectedGraph(int row, int col, int value){    if (row < 0 && row >= m_capacity) return false;    if (col < 0 && col >= m_capacity) return false;    m_pMatrix[row*m_capacity + col] = value;    m_pMatrix[col*m_capacity + row] = value;    return true;}void CMap::printMatrix(){    for (int i = 0; i < m_capacity; i++){        for (int j = 0; j < m_capacity; j++){            cout<<m_pMatrix[i*m_capacity + j]<<" ";        }        cout << endl;    }}//遍历void CMap::depthFirstTraverse(int nodeIndex){    int value = 0;    cout << m_pNodeArray[nodeIndex].m_data << " ";    m_pNodeArray[nodeIndex].m_isVisited = true;    for (int i = 0; i < m_capacity; i++){        //判断从当前节点到其他顶点c是否存在边或者弧        getValueFromMatrix(nodeIndex, i, value);        if (value == 1){            if (m_pNodeArray[i].m_isVisited){                continue;            }            else{                depthFirstTraverse(i);            }        }        else{            continue;        }    }}void CMap::depthFirstTraverse_self(int nodeIndex){    int value = 0;    cout << m_pNodeArray[nodeIndex].m_data << " ";    m_pNodeArray[nodeIndex].m_isVisited = true;    for (int i = 0; i < m_capacity; i++){        getValueFromMatrix(nodeIndex, i, value);        if (value !=0){            if (m_pNodeArray[i].m_isVisited == false){                depthFirstTraverse_self(i);            }        }    }}void CMap::breadthFirstTraverse(int nodeIndex){    int value = 0;    int temp = NULL;    queue<int> queue;    Node firstNode = NULL;    queue.push(nodeIndex);    m_pNodeArray[nodeIndex].m_isVisited = true;    while (!queue.empty()){        temp = queue.front();        firstNode = m_pNodeArray[temp];        cout << firstNode.m_data << " ";        queue.pop();        for (int i = 0; i < m_capacity; i++){            getValueFromMatrix(temp, i, value);            if (value != 0){                if (m_pNodeArray[i].m_isVisited == false){                    queue.push(i);                    m_pNodeArray[i].m_isVisited = true;                }            }        }    }}bool CMap::getValueFromMatrix(int row, int col, int& val){    if (row < 0 || row >= m_capacity){        return false;    }    if (col < 0 || col >= m_capacity){        return false;    }    val = m_pMatrix[row*m_capacity + col];}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_selected != true){            minWeight = edgeVec[i].m_weightValue;            break;        }    }    if (minWeight == 0){        return -1;    }    //从剩余的边中继续找,看看有没有比第一条边的值更小的边    for (; i < (int)edgeVec.size(); i++){        if (edgeVec[i].m_selected != true){            if (edgeVec[i].m_weightValue < minWeight){                minWeight = edgeVec[i].m_weightValue;                edgeIndex = i;            }        }    }    return edgeIndex;}void CMap::primTree(int nodeIndex){    int value = 0;    int edgeCount = 0;    vector<int> nodeVec;//描述顶点的集合    vector<Edge> edgeVec;//描述边的集合    cout << m_pNodeArray[nodeIndex].m_data << endl;    nodeVec.push_back(nodeIndex);    m_pNodeArray[nodeIndex].m_isVisited = true;    while (edgeCount < m_capacity - 1){        int temp = nodeVec.back();        int i = 0;        for (; i < m_capacity; i++){            getValueFromMatrix(temp, i, value);            if (value != 0){                if (m_pNodeArray[i].m_isVisited != true){                    Edge edge(temp, i, value);                    edgeVec.push_back(edge);                }            }        }        int edgeIndex=getMinEdge(edgeVec);        edgeVec[edgeIndex].m_selected = true;        cout << edgeVec[edgeIndex].m_nodeIndexA << "------" << edgeVec[edgeIndex].m_nodeIndexB << " ";        //将最小边放入最小生成树的边集合        m_edge[edgeCount] = edgeVec[edgeIndex];        edgeCount++;        //找出最小边所连接的另一个点,并将点放入点集合        int nextNodeIndex = edgeVec[edgeIndex].m_nodeIndexB;        nodeVec.push_back(nextNodeIndex);        m_pNodeArray[nextNodeIndex].m_isVisited = true;        cout << m_pNodeArray[nextNodeIndex].m_data << endl;    }}void CMap::mergeNodeSet(vector<int> &nodeSetA, vector<int>  nodeSetB){    for (int i = 0; i < nodeSetB.size(); i++){        nodeSetA.push_back(nodeSetB[i]);    }}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::kruskalTree(){    int value = 0;    int edgeCount = 0;    vector<vector<int>> nodeSets;    //得到所有边    vector<Edge> edgeVec;    for (int i = 0; i < m_capacity; i++){        for (int j = i + 1; j < m_capacity; j++){            getValueFromMatrix(i, j, value);            if (value != 0){                Edge edge(i, j, value);                edgeVec.push_back(edge);            }        }    }    //从所有边中取出组成最小生成树的边    //1.找到算法结束条件    //2.找到集合中的最小边    //3.找出最小边相连的点    //4.找出点所在的点集合    //5.根据点所在集合的不同做出不同处理    while (edgeCount < m_capacity - 1){        int minEdgeIndex = getMinEdge(edgeVec);        edgeVec[minEdgeIndex].m_selected = true;        int nodeAIndex=0, nodeBIndex = 0;        bool nodeAIsInSet = false;        bool nodeBIsInset = false;        nodeAIndex = edgeVec[minEdgeIndex].m_nodeIndexA;        nodeBIndex = edgeVec[minEdgeIndex].m_nodeIndexB;        int nodeAInSetLabel = -1;        int nodeBInsetLabel = -1;        for (int i = 0; i < (int)nodeSets.size(); i++){            //不可能有一个点同时存在两个集合中            nodeAIsInSet = isInset(nodeSets[i], nodeAIndex);            if (nodeAIsInSet){                nodeAInSetLabel = i;            }        }        for (int i = 0; i < (int)nodeSets.size(); i++){            //不可能有一个点同时存在两个集合中            nodeBIsInset = isInset(nodeSets[i], nodeBIndex);            if (nodeBIsInset){                nodeBInsetLabel = i;            }        }        if (nodeAInSetLabel == -1 && nodeBInsetLabel == -1){            vector<int> vec;            vec.push_back(nodeAIndex);            vec.push_back(nodeBIndex);            nodeSets.push_back(vec);        }        //A不属于任何集合,B属于某个集合        else if (nodeAInSetLabel == -1 && nodeBInsetLabel != -1){            nodeSets[nodeBInsetLabel].push_back(nodeAIndex);        }        else if (nodeBInsetLabel == -1 && nodeAInSetLabel != -1){            nodeSets[nodeAInSetLabel].push_back(nodeBInsetLabel);        }        //连接到两个集合中的不同点,需要合并两个集合        else if (nodeAInSetLabel != -1 && nodeBInsetLabel != -1 && nodeAInSetLabel != nodeBInsetLabel){            mergeNodeSet(nodeSets[nodeAInSetLabel], nodeSets[nodeBInsetLabel]);            for (int j = nodeBInsetLabel; j < (int)nodeSets.size() - 1; j++){                nodeSets[j] = nodeSets[j + 1];            }        }        //表示形成回路        else if (nodeAInSetLabel != -1 && nodeBInsetLabel != -1 && nodeAInSetLabel == nodeBInsetLabel){            continue;        }        m_edge[edgeCount] = edgeVec[minEdgeIndex];        edgeCount++;        cout << edgeVec[minEdgeIndex].m_nodeIndexA << "----" << edgeVec[minEdgeIndex].m_nodeIndexB << " ";        cout << edgeVec[minEdgeIndex].m_weightValue << endl;    }}

CMapDemo.cpp

#include <iostream>#include "CMap.h"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->depthFirstTraverse_self(0);    cout << "\n换一种方法试试看:" << endl;    pMap->resetNode();    pMap->depthFirstTraverse(0);    pMap->resetNode();    cout << "\n图的广度优先遍历:" << endl;    pMap->breadthFirstTraverse(0);    cout << endl;    return 0;}

CMapDemo_MiniGenerTree.cpp

#include <iostream>#include "CMap.h"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);    cout<<endl;    pMap->kruskalTree();    cout << endl;    return 0;}

PS:CMapDemo.cpp主要是针对图的遍历,广度深度优先进行的,CMapDemo_MiniGenerTree.cpp主要是针对图的最小生成树进行设计的,希望大家仔细品味。
CMap用到的图:
这里写图片描述
运行结果:
这里写图片描述
CMapDemo_MiniGenerTree.cpp用到的图:
这里写图片描述
运行结果:
这里写图片描述