• 有向图和无向图的数组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);
        }
    }
  • 相关阅读:
    【Canvas】摆线模拟
    【JS】JS正则表达式常见用法(验证、查找和替换)
    【Canvas】将屏幕坐标系转换成笛卡尔坐标系
    【Canvas】狗撵兔子和贝塞尔曲线
    精妙的SQL和SQL SERVER 与ACCESS、EXCEL的数据导入导出转换
    用Javascript实现HtmlEncode与HtmlDecode的另类方法
    [Javascript] 如何在客户端验证表单被改变
    关于IE6和IE7关闭窗口时提示和不提示以及上传图片前的本地预览解决办法
    项目开发经验谈(一)
    Windows 7 开发新特性
  • 原文地址:https://www.cnblogs.com/Java-Starter/p/9452026.html
Copyright © 2020-2023  润新知