有向圖和無向圖的數組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);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM