数据结构与算法(C++) -- 图的DFS 和 BFS based on adjMat queue-BFS stack-DFS

0. 概览

在这里插入图片描述

1. DFS

在这里插入图片描述
先从A->B->E->C,再返回C->E->B->A->D,但是要跳过搜索过的顶点,最后输出A->B->E->C->D
在这里插入图片描述

#include <iostream>
#include <stack>
using namespace std;

// 深度优先搜索算法
// 沿着顶点一直找,找到最后一个顶点,然后返回横向找, 不包括已经搜索过的点
// 使用堆栈更合适, 往回找时 先进后出FILO 后进先出LIFO
// 用邻接矩阵和stack 

#define MAXVERTEX_NUMS 20
class Graph;
class Vertex
{
    friend class Graph;
public:
    Vertex(const char dt): data(dt) { }
private:
    char data;
};
class Graph
{
public:
    Graph()
    : nVertex(0), vertexTable(new Vertex*[MAXVERTEX_NUMS]) // 初始化当前顶点个数 和 存放顶点的数组
    {
        for(int i=0; i<MAXVERTEX_NUMS; i++) // 初始化顶点状态
            visitedV[i] = 0; 

        for(int i=0; i<MAXVERTEX_NUMS; i++) // 初始化adjacency matrix
            for(int j=0; j<MAXVERTEX_NUMS; j++)
                adjMat[i][j] = 0;
    }
    ~Graph() { delete[] vertexTable; } // vertexTable中存放的不是new出来的Vertex, 所以只需delete数组即可
    void addVertex(Vertex& v);
    void addEdge(const Vertex& v1, const Vertex& v2);
    void printVertex() const;
    void printAdjMat() const; 
    void printDFS(); // ***********8重点是printDFS()****************
private:
    Vertex** vertexTable;                        // 存放顶点 
    bool visitedV[MAXVERTEX_NUMS];               // 存放顶点是否被遍历的状态
    bool adjMat[MAXVERTEX_NUMS][MAXVERTEX_NUMS]; // adjacency matrix
    int nVertex;                                 // 当前顶点个数 
};
void Graph::addVertex(Vertex& v)
{
    vertexTable[nVertex++] = &v;
}
void Graph::addEdge(const Vertex& v1, const Vertex& v2)
{
    adjMat[v1.data-65][v2.data-65] = 1;
    adjMat[v2.data-65][v1.data-65] = 1;
}
void Graph::printVertex() const
{
    for(int i=0; i<nVertex; i++)
        cout << vertexTable[i]->data << " ";
    cout << endl;
}
void Graph::printAdjMat() const
{
    for(int i=0; i<nVertex; i++)
    {    
        for(int j=0; j<nVertex; j++)
            cout << adjMat[i][j] << " ";
        cout << endl;
    }
}
// ----------------------------DFS---------------------------------------
void Graph::printDFS()
{
    auto vnextUnvisited = [&](const Vertex* v)->int // 返回顶点在vertexTable中的位置
    {
        for(int i=0; i<nVertex; i++)                  // 搜索adjacency matrix的每一行
            if(adjMat[v->data-65][i] && !visitedV[i]) // 如果给定顶点,在邻接表找到1 且 没被访问过
                return vertexTable[i]->data - 65;     // 返回该顶点对应表中的位置
        return -1; // 如果没找到返回-1
    };

    stack<Vertex*> gStack;  // 用stack存放 遍历过的 顶点 
    int i = 0;              // 记录顶点在vertexTable中的索引
    visitedV[i] = true;                  // 标记第一个顶点已被访问
    cout << vertexTable[i]->data << " "; // 输出
    gStack.push(vertexTable[i]);         // 压入起点
    while(!gStack.empty())
    {
        i = vnextUnvisited(gStack.top()); // 访问第下个顶点
        if(i >= 0) // 存在
        {
            visitedV[i] = true;                  // 标记被访问
            cout << vertexTable[i]->data << " "; // 输出
            gStack.push(vertexTable[i]);         // 压入
        }
        else // 没有下个顶点了
        {
            gStack.pop();
        }
    }
    cout << endl;
    for(int j=0; j<nVertex; j++) // 状态表置零  可以多次搜索
        visitedV[j] = false;
}
// -----------------------------------------------------------------------


int main()
{
    Vertex vA('A');    // 创建顶点
    Vertex vB('B');
    Vertex vC('C');
    Vertex vD('D');
    Vertex vE('E');

    Graph G;           // 创建图 
    G.addVertex(vA);   // 添加顶点
    G.addVertex(vB);
    G.addVertex(vC);
    G.addVertex(vD);
    G.addVertex(vE);
    G.addEdge(vA, vB); // 添加边
    G.addEdge(vA, vD);
    G.addEdge(vB, vE);
    G.addEdge(vD, vE);
    G.addEdge(vC, vE);

    G.printVertex();  // 打印顶点
    G.printAdjMat();  // 打印邻接矩阵

    cout << "=============\n";
    G.printDFS();     // 打印深度优先搜索结果
// output:
    // A B C D E 
    // 0 1 0 1 0 
    // 1 0 0 0 1 
    // 0 0 0 0 1 
    // 1 0 0 0 1 
    // 0 1 1 1 0 
    // =============
    // A B E C D 

    return 0;
}

2.BFS

在这里插入图片描述
先从A开始,一层一层的搜索,A->B->D->E->C
在这里插入图片描述

#include <iostream>
#include <stack>
#include <queue>
using namespace std;

// 广(宽)度优先搜索算法 Breadth First Search
// 顶点周围找,找完继续找下一个顶点的周围
// 先把第一个顶点周围的 顶点放入队列, 然后依次取出顶点,继续放入周围的队列 (一层一层的搜索)
// 使用队列,,  先放入的顶点先搜索周围其他顶点, 先进先出FIFO

#define MAXVERTEX_NUMS 20
class Graph;
class Vertex
{
    friend class Graph;
public:
    Vertex(const char dt): data(dt) { }
private:
    char data;
};
class Graph
{
public:
    Graph()
    : nVertex(0), vertexTable(new Vertex*[MAXVERTEX_NUMS]) // 初始化当前顶点个数 和 存放顶点的数组
    {
        for(int i=0; i<MAXVERTEX_NUMS; i++) // 初始化顶点状态
            visitedVtable[i] = 0; 

        for(int i=0; i<MAXVERTEX_NUMS; i++) // 初始化adjacency matrix
            for(int j=0; j<MAXVERTEX_NUMS; j++)
                adjMat[i][j] = 0;
    }
    ~Graph() { delete[] vertexTable; } // vertexTable中存放的不是new出来的Vertex, 所以只需delete数组即可
    void addVertex(Vertex& v);
    void addEdge(const Vertex& v1, const Vertex& v2);
    void printVertex() const;
    void printAdjMat() const; 
    void printDFS(); // ***********重点是printDFS()****************
    void printBFS(); // ***********重点是printBFS()****************
private:
    Vertex** vertexTable;                        // 存放顶点 
    bool visitedVtable[MAXVERTEX_NUMS];          // 存放顶点是否被遍历的状态
    bool adjMat[MAXVERTEX_NUMS][MAXVERTEX_NUMS]; // adjacency matrix
    int nVertex;                                 // 当前顶点个数 
};
void Graph::addVertex(Vertex& v)
{
    vertexTable[nVertex++] = &v;
}
void Graph::addEdge(const Vertex& v1, const Vertex& v2)
{
    adjMat[v1.data-65][v2.data-65] = 1;
    adjMat[v2.data-65][v1.data-65] = 1;
}
void Graph::printVertex() const
{
    for(int i=0; i<nVertex; i++)
        cout << vertexTable[i]->data << " ";
    cout << endl;
}
void Graph::printAdjMat() const
{
    for(int i=0; i<nVertex; i++)
    {    
        for(int j=0; j<nVertex; j++)
            cout << adjMat[i][j] << " ";
        cout << endl;
    }
}
// ----------------------------DFS---------------------------------------
void Graph::printDFS()
{
    auto vnextUnvisited = [&](const Vertex* v)->int // 返回顶点在vertexTable中的位置
    {
        for(int i=0; i<nVertex; i++)                       // 搜索adjacency matrix的每一行
            if(adjMat[v->data-65][i] && !visitedVtable[i]) // 如果给定顶点,在邻接表找到1 且 没被访问过
                return i;                                  // 返回该顶点对应表中的位置
        return -1; // 如果没找到返回-1
    };

    stack<Vertex*> gStack;  // 用stack存放 遍历过的 顶点 
    int i = 0;              // 记录顶点在vertexTable中的索引
    visitedVtable[i] = true;             // 标记第一个顶点已被访问
    cout << vertexTable[i]->data << " "; // 输出
    gStack.push(vertexTable[i]);         // 压入起点
    while(!gStack.empty())
    {
        i = vnextUnvisited(gStack.top()); // 访问第下个顶点
        if(i >= 0) // 存在
        {
            visitedVtable[i] = true;             // 标记被访问
            cout << vertexTable[i]->data << " "; // 输出
            gStack.push(vertexTable[i]);         // 访问过的顶点 都要压入stack
        }
        else // 没有下个顶点了
        {
            gStack.pop();
        }
    }
    cout << endl;
    for(int j=0; j<nVertex; j++) // 状态表置零  可以多次搜索
        visitedVtable[j] = false;
}
// -----------------------------------------------------------------------

// ----------------------------BFS----------------------------------------
void Graph::printBFS()
{
    auto vnextUnvisited = [&](Vertex* v) -> int
    {
        for(int i=0; i<nVertex; i++)
        {
            if(adjMat[v->data - 65][i] && !visitedVtable[i])
                return i;
            return -1;
        }   
    };

    queue<Vertex*> gQueue;       // 用于保存顶点
    int i = 0;                   // 用于保存当前顶点的索引
    visitedVtable[i] = true;     // 标记该顶点已被遍历
    gQueue.push(vertexTable[i]); // 存入queue
    while(!gQueue.empty()) // 遍历 queue里保存的 顶点
    {
        i = gQueue.front()->data - 65;          // 从queue中取出一个顶点,获取索引号
        int j = vnextUnvisited(gQueue.front()); // 记录 当前顶点下一个连接顶点 的起始位置, 记录adjMat的一行索引, 从第一个连接顶点开始                  // 
        while(j < nVertex) // 遍历完周围没有被 遍历过的 顶点
        {
            if(adjMat[i][j] && !visitedVtable[j]) // j对应的这个周围顶点 没有被遍历过的
            {
                visitedVtable[j] = true;          // 标记该顶点已被遍历
                gQueue.push(vertexTable[j]);      // 存入queue
            }
            j++;                                  // 寻找下一个 周围的顶点
        }
        cout << gQueue.front()->data << " "; // 当前顶点周围顶点都存进queue时, 输出当前节点
        gQueue.pop();                        // 并删除这个顶点,指向下一个
    }

    cout << endl;
    for(int ii=0; ii<nVertex; ii++) // 为方便多次搜索, 需要清零 是否被搜索过的记录
        visitedVtable[ii] = false;
}
// -----------------------------------------------------------------------


int main()
{
    Vertex vA('A');    // 创建顶点
    Vertex vB('B');
    Vertex vC('C');
    Vertex vD('D');
    Vertex vE('E');

    Graph G;           // 创建图 
    G.addVertex(vA);   // 添加顶点
    G.addVertex(vB);
    G.addVertex(vC);
    G.addVertex(vD);
    G.addVertex(vE);
    G.addEdge(vA, vB); // 添加边
    G.addEdge(vA, vD);
    G.addEdge(vB, vE);
    G.addEdge(vD, vE);
    G.addEdge(vC, vE);

    G.printVertex();  // 打印顶点
    G.printAdjMat();  // 打印邻接矩阵

    cout << "=============\n";
    G.printDFS();     // 打印深度优先搜索结果 DFS
    G.printBFS();     // 打印广度优先搜索结果 BFS
// output:
    // A B C D E 
    // 0 1 0 1 0 
    // 1 0 0 0 1 
    // 0 0 0 0 1 
    // 1 0 0 0 1 
    // 0 1 1 1 0 
    // =============
    // A B E C D 
    // A B D E C 

    return 0;
}

测试二,plus代码

在这里插入图片描述

// 邻接矩阵如下
    // 0 0 1 1 0 1 0
    // 0 0 1 0 0 0 0
    // 1 1 0 1 0 0 0 
    // 1 0 1 0 0 0 0
    // 0 0 0 0 0 0 1
    // 1 0 0 0 0 0 1
    
// DFS: A C B D F G E 
// BFS: A C D F B G E
#include<iostream>
#include <cstring>
#include<stack>
#include<queue>

using namespace std;

#define MAX_SIZE    (10)

template<typename T>
class Vertex
{
public:
    Vertex(const char n, const T& d=T())
    : name(n), data(d) { }
    char name;
    T data;
};

template<typename T>
class Graph
{
public:
    Graph()
    {
        theSize = 0;
        for (int i=0; i<MAX_SIZE; ++i) 
            for (int j=0; j<MAX_SIZE; ++j) 
                adjMat[i][j] = 0;
    }
    // 递归 或者 stack
    void DFS()
    {
        if (theSize == 0) return;

        bool visited[theSize];      // 记录被访问过的顶点
        memset(visited, 0, theSize);// 初始置0
        
        stack<Vertex<T>*> vStack;       // DFS栈
        int index = 0;                  // 记录没有访问过的顶点的索引
        Vertex<T>* first = vertexTable[index];
        cout << first->name << " ";     // visited
        visited[index] = true;          // 标记被访问           
        vStack.push(vertexTable[index]);// 第一个入栈
        while (!vStack.empty()) {
            auto p = vStack.top();      // 获取栈顶
            // 查找p点周围没有被访问过的点
            for (int i=0; i<theSize; ++i) {
                if (!visited[i] && adjMat[p->name - 'A'][i]) {
                    index = i;
                    break;
                } else index = -1;
            }
            // 该顶点周围的点都被访问过了
            if (index == -1) {
                vStack.pop();
            }
            // p周围还存在没被访问过的顶点,访问,入栈
            else {
                cout << vertexTable[index]->name << " ";
                visited[index] = true;  // 标记被访问           
                vStack.push(vertexTable[index]);
            }
        }
        cout << endl;
    }
    // queue 入q就标记被访问, pop只打印
    void BFS()
    {
        bool visited[theSize];
        memset(visited, 0, sizeof(visited));

        queue<Vertex<T>*> vQueue;
        vQueue.push(vertexTable[0]);        // 从第一个顶点开始
        visited[0] = true;                  // 标记

        while (!vQueue.empty()) {
            Vertex<T>* p = vQueue.front();  // 取出队头
            vQueue.pop();
            cout << p->name << " ";         // 打印
            // 周围的点都入queue, 没有被访问过且有连接关系
            for (int i=0; i<theSize; ++i) {
                if (!visited[i] && adjMat[p->name - 'A'][i]) {
                    vQueue.push(vertexTable[i]);                // 入queue
                    visited[vertexTable[i]->name - 'A'] = true; // 标记
                }
            }
        }
    }
    void add_vertex(Vertex<T>& v) { vertexTable[theSize++] = &v; }
    void add_edge(const Vertex<T>& v1, const Vertex<T>& v2) 
    {
        adjMat[v1.name - 'A'][v2.name - 'A'] = 1;   // 对称阵
        adjMat[v2.name - 'A'][v1.name - 'A'] = 1;   // 对称阵
    }
    void print_adjmat() const 
    { 
        for (int i=0; i<theSize; ++i) {
            for (int j=0; j<theSize; ++j) 
                cout << adjMat[i][j] << " ";
            cout << endl;
        }
    }
private:
    Vertex<T>* vertexTable[MAX_SIZE];
    bool adjMat[MAX_SIZE][MAX_SIZE];
    int theSize;
};


int main()
{
    Graph<string> gh;
    Vertex<string> vA('A');
    Vertex<string> vB('B');
    Vertex<string> vC('C');
    Vertex<string> vD('D');
    Vertex<string> vE('E');
    Vertex<string> vF('F');
    Vertex<string> vG('G');

    gh.add_vertex(vA);
    gh.add_vertex(vB);
    gh.add_vertex(vC);
    gh.add_vertex(vD);
    gh.add_vertex(vE);
    gh.add_vertex(vF);
    gh.add_vertex(vG);
    gh.print_adjmat(); cout << endl;

    gh.add_edge(vA, vC);
    gh.add_edge(vA, vD);
    gh.add_edge(vA, vF);
    gh.add_edge(vB, vC);
    gh.add_edge(vC, vD);
    gh.add_edge(vE, vG);
    gh.add_edge(vF, vG);
    gh.print_adjmat();

    gh.DFS();
    gh.BFS();

// stdout
    // 0 0 1 1 0 1 0
    // 0 0 1 0 0 0 0
    // 1 1 0 1 0 0 0 
    // 1 0 1 0 0 0 0
    // 0 0 0 0 0 0 1
    // 1 0 0 0 0 0 1
    // DFS: A C B D F G E 
    // BFS: A C D F B G E

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值