数据结构之图篇

一、图的基本概念及存储方式

在这里插入图片描述
在这里插入图片描述
图的存储结构:
在这里插入图片描述
邻接矩阵:

struct Node {
	顶点索引;
	顶点数据;
}
struct Map {
    顶点数组;
    邻接矩阵;
}

邻接表–链式存储
在这里插入图片描述

struct Node {
    顶点索引;
    该顶点弧链表的头节点;
    顶点数据;
}
struct Arc {
	指向的顶点索引;
	指向下一条弧的指针;
	弧信息;
}
struct Map {
	顶点数组;
}

十字链表–链式存储
在这里插入图片描述

struct Arc {
	弧尾顶点索引;
	弧头顶点索引;
	指向下一条弧头相同的弧的指针;
	指向下一条弧尾相同的弧的指针;
	弧信息;
}
struct Node {
	顶点索引;
	顶点数据;
	第一条入弧结点指针;
	第一条出弧结点指针;
}
struct Map {
	顶点数组;
}

邻接多重表 – 链表存储(无向图)
在这里插入图片描述

struct Arc {
	顶点A索引;
	顶点B索引;
	连接A的下一条边的指针;
	连接B的下一条边的指针;
	边信息;
}
struct Node {
	顶点索引;
	顶点数据;
	第一条边结点指针;
}
struct Map {
	顶点数组;
}

二、图的基本操作与遍历

图的遍历:深度优先搜素(前序优先搜索) 、广度优先搜索**
CMap.h

#define CMPA_H 
#include<vector>
#include "Edge.h"
#include "Node.h"
#include<iostream>
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 isInSet(vector<int> nodeSet,int target);
        void mergeNodeSet(vector<int> &nodeSetA,vector<int> nodeSetB);
        int getMinEdge(vector<Edge> edgeVec);
        bool getValueFromMatrix(int row, int col, int &val); //从矩阵中获取权值 
        void breadthFirstTraverseImpl(vector<int> preVec);  //广度优先遍历实现函数 
        int m_iCapacity; //图中最多可以容纳的顶点数 
        int m_iNodeCount; // 已经添加的顶点(结点)个数 
        Node *m_pNodeArray; //用来存放顶点数组 
        int *m_pMatrix; //用来存放邻接矩阵         
        Edge *m_pEdge; 
};
CMap::CMap(int capacity) {
    m_iCapacity = 0;
    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)); 
    m_pEdge = new Edge[m_iCapacity-1];
}
 
CMap::~CMap() {
    delete []m_pNodeArray;
    delete []m_pMatrix;
}
void CMap::resetNode() {
    for(int i = 0; i < m_iNodeCount; i++) {
       m_pNodeArray[i].m_bIsVisited = false; 
    }
}
bool CMap::addNode(Node *pNode) {
    m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData;
    m_iNodeCount++;
    return true;
}
bool CMap::setValueToMatrixForDirectedGraph(int row,int col,int val) {
    m_pMatrix[row*m_iCapacity + col] = val;
    return true;
}
bool CMap::setValueToMatrixForUndirectedGraph(int row,int col,int val) {
    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) {
     val = m_pMatrix[row*m_iCapacity + col];
     return true;
}
void CMap::breadthFirstTraverseImpl(vector<int> preVec) {
    int value = 0;
    vector<int> curVec;   
    for(int j = 0; j < (int)preVec.size(); j++) {
        for(int k = 0; k < m_iCapacity; k++) {
            getValueFromMatrix(preVec[j],k,value);
            if(value != 0) {
             if(m_pNodeArray[k].m_bIsVisited) {
                continue;
              } else {
                cout << m_pNodeArray[k].m_cData << " ";
                m_pNodeArray[k].m_bIsVisited = true;
                
                curVec.push_back(k);
              }
            }
        }
    }
    if(curVec.size() == 0) {
        return;
    } else {
        breadthFirstTraverseImpl(curVec);
    }
}
void CMap::printMatrix() {
    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);
            }
        }
    } 
}
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);
}

Node.h

#ifndef NODE_H
#define NODE_H
#include<iostream>
using namespace std;
class Node{
    public:
       Node(char data = 0);
       char m_cData;
       bool m_bIsVisited; 
};
Node::Node(char data) {
    m_cData = data;
    m_bIsVisited = false;
}
#endif

三、图的最小生成树算法

普利姆算法

Edge.h

#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;
};
Edge::Edge(int nodeIndexA,int nodeIndexB,int weightValue) {
    m_iNodeIndexA = nodeIndexA;
    m_iNodeIndexB = nodeIndexB;
    m_iWeightValue = weightValue;
    m_bSelected = false;
}
#endif

CMap.h

	CMap::CMap(int capacity) {
	    m_iCapacity = 0;
	    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)); 
	    m_pEdge = new Edge[m_iCapacity-1];
	}
	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);
	    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 << "   " << 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;
	         
	    }
	
	}
	int CMap::getMinEdge(vector<Edge> edgeVec) {
	    int minWeight = 0;
	    int edgeIndex = 0;
	    for(int i = 0; i < edgeVec.size(); i++) {
	        if(!edgeVec[i].m_bSelected) {
	            minWeight = edgeVec[i].m_iWeightValue;
	            edgeIndex = i;
	        }
	    }
	    if(minWeight == 0) {
	        return -1;
	    }
	    for(int i = 0; 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;
	}
克鲁斯卡尔算法
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);
              }
        }
    }
    //从可选边集合中找出最小的边
    while (edgeCount < m_iCapacity - 1) {
        int minEdgeIndex =  getMinEdge(edgeVec);
        edgeVec[minEdgeIndex].m_bSelected = true;
        int nodeAIndex = edgeVec[minEdgeIndex].m_iNodeIndexA;
        int nodeBIndex = edgeVec[minEdgeIndex].m_iNodeIndexB;
        bool nodeAIsInSet = false;
        bool nodeBIsInSet = false;
        int nodeAInSetLabel = -1;
        int nodeBInSetLabel = -1;
        for(int i = 0; i < nodeSets.size(); i++) {
            nodeAIsInSet = isInSet(nodeSets[i],nodeAIndex);
            if(nodeAIsInSet) {
                nodeAInSetLabel = i;
            }
        }
        for(int i = 0; i < 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);
        }
        else if(nodeAInSetLabel == -1 && nodeBInSetLabel != -1) {
            nodeSets[nodeBInSetLabel].push_back(nodeAIndex);
        }
        else if(nodeAInSetLabel != -1 && nodeBInSetLabel == -1) {
            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) {
            continue;
        } 
        m_pEdge[edgeCount] = edgeVec[minEdgeIndex];
        edgeCount++;
    }
} 
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]);  
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值