C++图的操作

1 篇文章 0 订阅

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

Node.h

#ifndef NODE_H
#define NODE_H

class Node{
public:
    Node(char data = 0);
    char m_data;
    bool m_isVisited;

};
#endif

Edge.h

#ifndef EDGE_H
#define EDGE_H
class 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用到的图:
这里写图片描述
运行结果:
这里写图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值