有向图和无向图的数组C++实现

源码:https://github.com/cjy513203427/C_Program_Base/tree/master/55.%E5%9B%BE

结点类Noded.h

不需要存储索引

#pragma once
#ifndef NODE_H
#define NODE_H
#include<iostream>
using namespace std;

class Node
{
public:
    Node(char data = 0);
    char m_cData;
    bool m_IsVisited;
};

#endif // !NODE_H

Node.cpp

将数据赋值给数据成员m_cData,是否访问置为否

#include"Node.h"

Node::Node(char data)
{
    m_cData = data;
    m_IsVisited = false;
}

需要实现的方法

图类cMap.h

#pragma once
#ifndef CMAP_H
#define CMAP_H
#include"Node.h"
#include<vector>
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 breathFirstTraverseImpl(vector<int> preVec);

private:
    bool getValueFromMatrix(int row,int col,int &val);//从矩阵中获取权值
    void breathFirstTraverse(int nodeIndex);//广度优先遍历实现函数

private:
    int m_iCapacity;//图中最多可以容纳的顶点数
    int m_iNodeCount;//已经添加的结点(顶点)个数
    Node *m_pNodeArray;//用来存放顶点数组
    int *m_pMatrix;//用来存放邻接矩阵
};

#endif // !CMAP_H

构造函数:

传入图容量参数给数据成员m_iCapacity

已经添加的结点数m_iNodeCount置为0

为顶点数组申请内存

申请m_iCapacity*m_iCapacity的矩阵

将矩阵元素全部置为0

cMap::cMap(int capacity)
{
    m_iCapacity = capacity;
    m_iNodeCount = 0;
    m_pNodeArray = new Node[m_iCapacity];
    m_pMatrix = new int[m_iCapacity*m_iCapacity];
    for (int i = 0; i < m_iCapacity*m_iCapacity; i++)
    {
        m_pMatrix[i] = 0;
    }
}

析构函数

删除顶点数组指针

删除邻接矩阵指针

cMap::~cMap()
{
    delete []m_pNodeArray;
    delete []m_pMatrix;
}

添加结点

判断传入的pNode参数是否为空,如果pNode为空,返回错误

将pNode的数据部分m_cData传入到以已经添加的结点个数为索引的顶点数组

已经添加结点个数++

返回正确结果

bool cMap::addNode(Node *pNode)
{
    if (pNode == NULL) 
    {
        return false;
    }
    m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData;
    m_iNodeCount++;
    return true;
}

重置结点

将已经添加的结点的m_IsVisited置为未访问

void cMap::resetNode()
{
    for (int i = 0; i < m_iNodeCount; i++)
    {
        m_pNodeArray[i].m_IsVisited = false;
    }
}

为有向图设置邻接矩阵

判断行列的合法性

如果行小于0,行大于等于最大容量,返回错误

如果列小于0,列大于等于最大容量,返回错误

图如下:

上图的邻接矩阵如下:

以(A,B)即(0,1),0行1列,0*8+1=1。

满足row*m_iCapacity计算的索引

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;
}

为无向图设置邻接矩阵

逻辑同上

col*m_iCapacity和row*m_iCapacity+col与主对角线成轴对称

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;
}

从矩阵中获取权值

先判断行和列的合法性

行不能小于0,不能大于等于容量

列不能小于0,不能大于等于容量

获取当前索引的邻接矩阵,赋值给变量返回

返回正确结果

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;
}

打印邻接矩阵

矩阵,用两层循环遍历

i是row,k就是col

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;
    }
}

深度优先遍历

深度优先遍历相当于树的前序遍历

先直接输出当前指定索引的邻接矩阵的结点

讲m_IsVisited置为未访问

按序获取获取矩阵权值

如果权值不等于1,跳过本次循环

 

如果权值等于1,结点已访问,跳过本次循环,这里是无向图,这里判断结点是否访问是因为邻接矩阵的权值1成主对角线对称,防止A-B访问,再访问B-A的情况出现

如果未访问,进入递归,进入方法前两行,将结点输出,以此类推

看懂过程要打断点

void cMap::depthFirstTraverse(int nodeIndex)
{
    int value = 0;
    cout << m_pNodeArray[nodeIndex].m_cData<<" ";
    m_pNodeArray[nodeIndex].m_IsVisited = true;

    for (int i = 0; i < m_iCapacity; i++)
    {
        getValueFromMatrix(nodeIndex,i,value);
        if (value == 1)
        {
            if (m_pNodeArray[i].m_IsVisited == true)
            {
                continue;
            }
            else
            {
                depthFirstTraverse(i);
            }
        }
        else
        {
            continue;
        }
    }
}

广度优先遍历

广度优先遍历相当于按层次的树的前序遍历

思路:将上层结点放到一个vector里,该结点的下层结点再放到一个vector里

void cMap::breadthFirstTraverse(int nodeIndex)
{
    cout << m_pNodeArray[nodeIndex].m_cData<<" ";
    m_pNodeArray[nodeIndex].m_IsVisited = true;

    vector<int> currentVec;
    currentVec.push_back(nodeIndex);

    breathFirstTraverseImpl(currentVec);
}

void cMap::breathFirstTraverseImpl(vector<int> preVec)
{
    int value = 0;
    vector<int> curVec;

    for (int j = 0; j < (int)preVec.size(); j++)
    {
        for (int i = 0; i < m_iNodeCount; i++)
        {
            getValueFromMatrix(preVec[j],i,value);
            if (value != 0)
            {
                if (m_pNodeArray[i].m_IsVisited)
                {
                    continue;
                }
                else
                {
                    cout << m_pNodeArray[i].m_cData << " ";
                    m_pNodeArray[i].m_IsVisited = true;

                    curVec.push_back(i);
                }
            }
        }
    }
    if (curVec.size() == 0)
    {
        return;
    }
    else
    {
        breathFirstTraverseImpl(curVec);
    }
}

 

posted @ 2018-08-09 22:01  Rest探路者  阅读(2740)  评论(0编辑  收藏  举报
levels of contents