数据结构-图(图的基本实现C++)

​一、图的概念

图是一种比较复杂的非线性数据结构

图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。

图区分有向图和无向图

1、无向图(Undirected graphs)

如果图中任意两个顶点之间的边都是无向边,则称该图为无向图。

无向图相关概念:顶点、边

2、有向图(Directed graphs)

如果图中任意两个顶点之间的边都是有向边,则称该图为有向图

有向图相关概念:顶点、弧(弧头、弧尾  出度、入度)

另外,有些图的边或弧具有与它相关的数值,这种与图的边或弧相关的数值叫做权(Weight),这是一个求最小生成树的关键值。

二、图的存储

图的存储结构要存储图中的各个顶点本身的信息,以及存储顶点与顶点之间的关系,比较复杂。图的存储结构有邻接矩阵、邻接表、十字链表、邻接多重表等。

三、图的遍历

图的遍历思想是从指定一个顶点出发,开始访问其他顶点,不能重复访问(每个顶点只能访问一次),直至所有点被访问。

1.深度优先遍历(depth_first_search)

思想:从指定的第一个点开始,沿着向下的定点不重复的一直遍历下去,若走到尽头,退到上一个顶点,寻找附近有没有顶点,有而且不重复的话,接着遍历,否则退到上一个顶点。

2.广度优先遍历(breadth_first_search)

思想:从指定的第一点开始,先寻找跟它直接相连的所有顶点,然后继续这几个顶点再次深入,每次搜寻的都是同一级别的。

四、最小生成树

1、普利姆(Prim)算法

思路:首先就是从图中的一个起点a开始,把a加入U集合,然后,寻找从与a有关联的边中,权重最小的那条边并且该边的终点b在顶点集合:(V-U)中,我们也把b加入到集合U中,并且输出边(a,b)的信息,这样我们的集合U就有:{a,b},然后,我们寻找与a关联和b关联的边中,权重最小的那条边并且该边的终点在集合:(V-U)中,我们把c加入到集合U中,并且输出对应的那条边的信息,这样我们的集合U就有:{a,b,c}这三个元素了,一次类推,直到所有顶点都加入到了集合U

2、克鲁斯卡尔(Kruskal)算法

思路:1.将图中的所有边都去掉;2.将边按权值从小到大的顺序添加到图中,保证添加的过程中不会形成环;3.重复上一步直到连接所有顶点,此时就生成了最小生成树。这是一种贪心策略。

终于到了最兴奋的代码时候,代码说明一切!奥利给!

树的邻接矩阵表示法C++基本实现:

#ifndef _CMAP_H_
#define _CMAP_H_
​
​
#include <iostream>
#include <vector>
#include <assert.h>
using namespace std;
​
//顶点
class Node
{
public:
  Node(char data = 0)
  {
    m_cData = data;
    m_bVisited = false;
  }
  Node(const Node& node)
  {
    if (this == &node)
      return;
    *this = node;
  }
​
​
  Node& operator=(const Node& node)
  {
    if (this == &node)
      return *this;
    this->m_cData = node.m_cData;
    this->m_bVisited = node.m_bVisited;
    return *this;
  }
public:
  char m_cData; //数据
  bool m_bVisited; //是否访问
};
​
//边
class Edge
{
public:
  Edge(int nodeIndexA = 0, int nodeIndexB = 0, int weightValue = 0) :
    m_iNodeIndexA(nodeIndexA),
    m_iNodeIndexB(nodeIndexB),
    m_iWeightValue(weightValue),
    m_bSelected(false) {}
  Edge(const Edge& edge)
  {
    if (this == &edge)
      return;
    *this = edge;
  }
​
  Edge& operator=(const Edge& edge)
  {
    if (this == &edge)
      return *this;
    this->m_iNodeIndexA = edge.m_iNodeIndexA;
    this->m_iNodeIndexB = edge.m_iNodeIndexB;
    this->m_iWeightValue = edge.m_iWeightValue;
    this->m_bSelected = edge.m_bSelected;
    return *this;
  }
​
public:
  int m_iNodeIndexA; //头顶点
  int m_iNodeIndexB; //尾顶点
  int m_iWeightValue; //权重
  bool m_bSelected; //是否被选中
};
​
  //图
class CMap
{
​
private:
  int m_iCapacity; //顶点总数
  int m_iNodeCount; //当前顶点数量
  Node *m_pNodeArray; //顶点集合
  int *m_pMatrix; //邻接距阵
  Edge *m_pEdgeArray; //最小生成树边集合
public:
  CMap(int iCapacity)
  {
    m_iCapacity = iCapacity;
    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_pEdgeArray = new Edge[m_iCapacity - 1];
  }
  ~CMap(void)
  {
    delete[]m_pNodeArray;
    delete[]m_pMatrix;
    delete[]m_pEdgeArray;
  }
​
private:
  //广度遍历具体实现
  void breadthFirstTraverseImpl(vector<int> preVec)
{
    int val = 0;
    vector<int> curVec;
    for (int i = 0; i < (int)preVec.size(); i++)
    {
      for (int j = 0; j < m_iCapacity; j++)
      {
        getValueFromMatrix(preVec[i], j, val);
        if (/*1 == val*/0 != val)
        {
          if (m_pNodeArray[j].m_bVisited)
            continue;
          cout << m_pNodeArray[j].m_cData << " ";
          m_pNodeArray[j].m_bVisited = true;
          curVec.push_back(j);
        }
        else
          continue;
      }
    }
​
    if (curVec.empty())
      return;
    else
      breadthFirstTraverseImpl(curVec);
  }
​
  //取最小边
  int getMinEdge(const vector<Edge>& edgeVec)
{
    int min = 0, minEdge = 0;
​
    for (int i = 0; i < (int)edgeVec.size(); i++)
    {
      if (edgeVec[i].m_bSelected)
        continue;
      min = edgeVec[i].m_iWeightValue;
      minEdge = i;
    }
​
    for (int i = 0; i < (int)edgeVec.size(); i++)
    {
      if (edgeVec[i].m_bSelected)
        continue;
      if (min > edgeVec[i].m_iWeightValue)
      {
        min = edgeVec[i].m_iWeightValue;
        minEdge = i;
      }
    }
​
    if (0 == min)
      return -1;
​
    return minEdge;
  }
​
  bool isInSet(const vector<int>& nodeSet, int target)
{
    for (int i = 0; i < (int)nodeSet.size(); i++)
    {
      if (nodeSet[i] == target)
        return true;
    }
​
    return false;
  }
​
  void mergeNodeSet(vector<int>& nodeSetA, const vector<int>& nodeSetB)
{
    for (size_t i = 0; i < (int)nodeSetB.size(); i++)
    {
      nodeSetA.push_back(nodeSetB[i]);
    }
  }
public:
  //添加顶点
  void addNode(Node *node)
{
    assert(node);
    m_pNodeArray[m_iNodeCount].m_cData = node->m_cData;
    m_iNodeCount++;
  }
  //将顶点访问设置默认
  void resetNode()
{
    for (int i = 0; i < m_iNodeCount; i++)
      m_pNodeArray[i].m_bVisited = false;
  }
  //设置权重-有向图
  bool setValueToMatrixForDirectedGraph(int row, int col, int val = 1)
{
    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 setValueToMatrixForUndirectedGraph(int row, int col, int val = 1)
{
    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 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 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 depthFirstTraverse(int index)
{
    int val = 0;
    cout << m_pNodeArray[index].m_cData << " ";
    m_pNodeArray[index].m_bVisited = true;
​
    for (int i = 0; i < m_iCapacity; i++)
    {
      getValueFromMatrix(index, i, val);
      if (/*1 == val*/0 != val)
      {
        if (m_pNodeArray[i].m_bVisited)
          continue;
        depthFirstTraverse(i);
      }
      else
        continue;
    }
  }
​
  //广度遍历
  void breadthFirstTraverse(int index)
{
    cout << m_pNodeArray[index].m_cData << " ";
    m_pNodeArray[index].m_bVisited = true;
​
    vector<int> curVec;
    curVec.push_back(index);
​
    breadthFirstTraverseImpl(curVec);
  }
​
  //求最小生成树-普里斯算法
  void primTree(int index)
{
    int val = 0;
    int iEdgeCount = 0;
    vector<Edge> edgeVec;//待选边集合
​
    //从传入点开始找
    vector<int> nodeIndexVec;
    nodeIndexVec.push_back(index);
​
    //结束条件:边数=顶点数-1
    while (iEdgeCount < m_iCapacity - 1)
    {
      //查找传入点的符合要求(权重不为0且目的点没有被访问)边
      int row = nodeIndexVec.back();
      cout << m_pNodeArray[row].m_cData << endl;
      m_pNodeArray[row].m_bVisited = true;
​
      for (int i = 0; i < m_iCapacity; i++)
      {
        getValueFromMatrix(row, i, val);
        if (0 == val)
          continue;
        if (m_pNodeArray[i].m_bVisited)
          continue;
        Edge edge(row, i, val);
        edgeVec.push_back(edge);
      }
​
      //取出最小边
      int retIndex = getMinEdge(edgeVec);
      if (-1 != retIndex)
      {
        //存储选中边
        edgeVec[retIndex].m_bSelected = true;
        m_pEdgeArray[iEdgeCount] = edgeVec[retIndex];
        cout << m_pNodeArray[m_pEdgeArray[iEdgeCount].m_iNodeIndexA].m_cData << " - ";
        cout << m_pNodeArray[m_pEdgeArray[iEdgeCount].m_iNodeIndexB].m_cData << " (";
        cout << m_pEdgeArray[iEdgeCount].m_iWeightValue << ") " << endl;
        iEdgeCount++;
​
        int iNodeIndex = edgeVec[retIndex].m_iNodeIndexB;
        //设置点被访问
        m_pNodeArray[iNodeIndex].m_bVisited = true;
        //存入目的点递归查找
        nodeIndexVec.push_back(iNodeIndex);
      }
    }
​
  }
​
  //最小生成树-克鲁斯卡尔算法
  void kruskalTree()
{
    int val = 0;
    int edgeCount = 0;
​
    //定义存放节点集合数组
    vector<vector<int> > nodeSets;
​
    //第一步、取出所有边
    vector<Edge> edgeVec;
    for (int i = 0; i < m_iCapacity; i++)
    {
      for (int j = i + 1; j < m_iCapacity; j++)
      {
        getValueFromMatrix(i, j, val);
        if (0 == val)
          continue;
        if (m_pNodeArray[i].m_bVisited)
          continue;
        Edge edge(i, j, val);
        edgeVec.push_back(edge);
      }
    }
​
    //第二步、从所有边中取出组成最小生成树的边
    //1、算法结束条件:边数=顶点数-1
    while (edgeCount < m_iCapacity - 1)
    {
      //2、从边集合中找出最小边
      int retIndex = getMinEdge(edgeVec);
      if (-1 != retIndex)
      {
        edgeVec[retIndex].m_bSelected = true;
​
        //3、找出最小边连接点
        int nodeAIndex = edgeVec[retIndex].m_iNodeIndexA;
        int nodeBIndex = edgeVec[retIndex].m_iNodeIndexB;
​
        //4、找出点所在集合
        bool nodeAInSet = false;
        bool nodeBInSet = false;
        int nodeAInSetLabel = -1;
        int nodeBInSetLabel = -1;
​
        for (int i = 0; i < (int)nodeSets.size(); i++)
        {
          nodeAInSet = isInSet(nodeSets[i], nodeAIndex);
          if (nodeAInSet)
            nodeAInSetLabel = i;
        }
​
        for (int i = 0; i < (int)nodeSets.size(); i++)
        {
          nodeBInSet = isInSet(nodeSets[i], nodeBIndex);
          if (nodeBInSet)
            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)
        {
          nodeSets[nodeBInSetLabel].push_back(nodeAIndex);
        }
        else if (nodeAInSetLabel != -1 && nodeBInSetLabel == -1)
        {
          nodeSets[nodeAInSetLabel].push_back(nodeBIndex);
        }
        else if (-1 != nodeAInSetLabel && -1 != nodeBInSetLabel && nodeAInSetLabel != nodeBInSetLabel)
        {
          //mergeNodeSet(nodeSets[nodeAInSetLabel], nodeSets[nodeBInSetLabel]);
          nodeSets[nodeAInSetLabel].insert(nodeSets[nodeAInSetLabel].end(),
            nodeSets[nodeBInSetLabel].begin(),
            nodeSets[nodeBInSetLabel].end());
          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_pEdgeArray[edgeCount] = edgeVec[retIndex];
        edgeCount++;
​
        cout << m_pNodeArray[edgeVec[retIndex].m_iNodeIndexA].m_cData << " - ";
        cout << m_pNodeArray[edgeVec[retIndex].m_iNodeIndexB].m_cData << " (";
        cout << edgeVec[retIndex].m_iWeightValue << ") " << endl;
      }
    }
  }
};
​
#endif // !_CMAP_H_

 

测试树结构:

 

测试函数main.cpp:

#include "CMap.hpp"
#include <iostream>
using namespace std;
int main(int argc, char**argv)
{
​
  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, 7);
  pMap->setValueToMatrixForUndirectedGraph(0, 2, 1);
  pMap->setValueToMatrixForUndirectedGraph(0, 3, 9);
  pMap->setValueToMatrixForUndirectedGraph(1, 2, 2);
  pMap->setValueToMatrixForUndirectedGraph(1, 4, 3);
  pMap->setValueToMatrixForUndirectedGraph(2, 3, 11);
  pMap->setValueToMatrixForUndirectedGraph(2, 4, 8);
  pMap->setValueToMatrixForUndirectedGraph(2, 5, 4);
  pMap->setValueToMatrixForUndirectedGraph(3, 5, 5);
  pMap->setValueToMatrixForUndirectedGraph(4, 5, 15);
​
  cout << "打印矩阵: " << endl;
  pMap->printMatrix();
  cout << endl;
​
  pMap->resetNode();
​
  cout << "深度优先遍历: " << endl;
  pMap->depthFirstTraverse(0);
  cout << endl;
​
  pMap->resetNode();
​
  cout << "广度优先遍历: " << endl;
  pMap->breadthFirstTraverse(0);
  cout << endl;
​
  pMap->resetNode();
​
  cout << "普里姆算法: " << endl;
  pMap->primTree(0);
  cout << endl;
​
  pMap->resetNode();
​
  cout << "克鲁斯卡尔算法: " << endl;
  pMap->kruskalTree();
  cout << endl;
​
  pMap->resetNode();
​
  system("pause");
  return 0;
}

执行结果:

 

 

 

--|END|--


 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值