深度搜索和广度搜索是什么?代码怎么实现?

31 篇文章 1 订阅
12 篇文章 0 订阅

目录

一、概念

二、C++实现代码


一、概念

        深度、广度搜索是图中遍历搜索的两种算法。

        深度搜索DFS:一直往下查找,直到到头走不动了,往回走上一个分支,在该分支内一直往下走,循环这样走。

        对下左图进行如右图的深度搜索:从顶点A开始遍历,接着遍历A的第一个邻接顶点继续从B开始遍历B的第一个邻接顶点C,接着从C始遍历C的第一个邻接顶点D...直到遍历到F,F的第一个临界顶点已经被遍历,则遍历F的下一个邻接顶点G,接着从G的第一个邻接顶点遍历。

        假设最外圈是第一个临界顶点(图里面先假设,而代码具体在创建时要根据邻接表的存储顺序来看)A->B->C->D->E->F->G->H(此时H的临界结点都被访问过,回到G的位置,G的邻接结点也都被访问过了,回到F....一直回到了D,开始访问D下一个未被放过的结点)->I

        广度搜索BFS:所有只走一次,要标记被访问过的结点。

        对下左图进行广度搜索: 从顶点A开始遍历,接着遍历A的第一个邻接顶点B继续从B开始遍历B的第一个邻接顶点C,接着从C开始遍历C的第一个邻接顶点D.直到遍历到F,F的第一个临界顶点已经被遍历,则遍历F的下一个邻接顶点G,接着从G的第一个邻接顶点遍历

        A->B->F,对A为访问过的邻接结点一直入队,直到都入进去

        B->C->I->G,当A的邻接结点都入队后,判断队列是否为空,队列不空,将队头元素B出队,开始依次对队头元素的邻接结点入队

        F->E,当B的邻接结点都入队后,判断队列是否为空,队列不空,将队头元素F出队,开始依次对队头元素的邻接结点入队

        .....

        直到队为空,结束。

总结:

  1. 深度是到达一个顶点后就开始往下走,一条路走到黑(就像走迷宫一样,把一条路走到死)
  2. 广度:到达一个顶点后把与该顶点相连的所有结点都访问一下
  • 深度 -> 递归,类似于树的前序遍历
  • 广度 -> 非递归,类似于树的前序层遍历

二、C++实现代码

BFS

void Graph::BFS(char v)
{
    queue<int>qq;
    bool* visited = new bool[m_NumVertex];
    int front;
    Edge* p = NULL;
    for (int i = 0; i < m_NumVertex; i++)
    {
        visited[i] = false;
    }
    int vindex = GetVertexIndex(v);
    if (vindex == -1)
    {
        return;//说明不存在该顶点
    }
    qq.push(vindex);
    cout << v << " ";
    visited[vindex] = true;
    while (!qq.empty())//当队列不空,获取队头元素出队
    {
        front = qq.front;
        qq.pop();
        //访问队头元素的邻接顶点
        p = m_Vertex[vindex].m_list;//让p指向队头元素的邻接表,用邻接表访问邻接结点
        while (p)//有邻接顶点
        {
            if (!visited[p->m_destindex])//未被访问
            {
                cout << m_VerArr[p->m_destindex].m_value;//输出该结点的值
                visited[p->m_destindex] = true;
                qq.push(p->m_destindex);
            }
            p = p->m_next;
        }
    }
    delete[]visited;
    visited = NULL;

}

DFS

void Graph::DFS(char v)
{
    bool* visited = new bool[m_NumVertex];
    for (int i = 0; i < m_NumVertex; i++)
    {
        visited[i] = false;
    }
    int vindex = GetVertexIndex(v);
    if (vindex == -1)
        return;
    DFS(vindex,visited);//递归调用
    delete[]visited;
    visited = NULL;
}

void Graph::DFS(int v, bool* visited)//递归
{
    cout << m_VerArr[v].m_value << " ";
    visited[v] = true;
    Edge* p = m_VerArr[v].m_list;//p指向邻接表
    while (p)
    {
        if (!visited[p->m_destindex])
            DFS(p->m_destindex);
        p = p->m_next;
    }
}

完整代码


#include<iostream>
#include<queue>

using namespace std;
#define SIZE 10

class Edge//边
{
public:
    Edge() :m_next(NULL) {}
    Edge(int index) :m_destindex(index), m_next(NULL) {}
    int m_destindex;
    Edge* m_next;
};

class Vertex//顶点
{
public:
    Vertex():m_list(NULL){}
    Vertex(char v):m_value(v),m_list(NULL){}
    char m_value;
    Edge* m_list;
};
//图存储顶点的一维数组
class Graph
{
public:
    Graph();
    ~Graph();
    void InsertVertex(char v);//插入顶点
    void InsertEdge(char v1, char v2);//边
    int GetVertexIndex(char v);//获得顶点下标
    void ShowGraph();
    void BFS(char v);
    void DFS(char v);
    void DFS(int vindex, bool* visited);
    void DeleteEdge(char v1, char v2);//删除边函数
    void DeleteVertex(char v);//删除顶点函数
private:
    int m_MaxVertex;//最大能存储的顶点个数
    int m_NumVertex;//实际存储的个数
    //Vertex* m_VerArr;
    Vertex m_VerArr[SIZE];
};
Graph::Graph()
{
    m_MaxVertex = SIZE;
    m_NumVertex = 0;
    //m_VerArr = new Vertex[m_MaxVertex];
}
Graph::~Graph()
{
 /*   if (m_VerArr != NULL)
    {
        delete[]m_VerArr;
        m_VerArr = NULL;
    }*/
    m_NumVertex = 0;
}
void Graph::InsertVertex(char v)
{
    if (m_NumVertex >= m_MaxVertex)//空间满了就不放
        return;
    //没满就放
    m_VerArr[m_NumVertex++].m_value = v;
}

int Graph::GetVertexIndex(char v)
{
    //循环查找
    for (int i = 0; i < m_NumVertex; i++)
    {
        if (m_VerArr[i].m_value == v)//找到返回下标
            return i;
    }
    return -1;//没找到
}
void Graph::InsertEdge(char v1, char v2)
{
    //1.获得顶点下标,没有该下标(下标=-1)
    int p1index = GetVertexIndex(v1);
    int p2index = GetVertexIndex(v1);
    if (p1index == -1 || p2index == -1)
    {
        return;//任有一个不存在就返回
    }
    //插入v1到v2的边,头插法把p2的结点插入到p1前面
    Edge* p = new Edge(p2index);//new出p2的结点
    p->m_next = m_VerArr[p1index].m_list;//p2的头
    m_VerArr[p1index].m_list = p;//然后把头挪到P的位置
    //v2到v1,同理操作
    p = new Edge(p1index);
    p->m_next = m_VerArr[p2index].m_list;
    m_VerArr[p2index].m_list = p;
}

void Graph::ShowGraph()
{
    Edge* p = NULL;
    for (int i = 0; i < m_MaxVertex; i++)
    {
        cout << i << " " << m_VerArr[i].m_value << "->";//先把每个顶点输出
        p = m_VerArr[i].m_list;//让p=边链表的头
        while (p != NULL)
        {
            cout << p->m_destindex << "-》";
            p = p->m_next;
        }
    }
}
//删除边
void Graph::DeleteEdge(char v1, char v2)
{
    int p1index = GetVertexIndex(v1);
    int p2index = GetVertexIndex(v2);
    if (p1index == -1 || p2index == -1)//没找到
        return;
    //先删除v1到v2
    Edge* pf = NULL;
    Edge* p = m_VerArr[p1index].m_list;//p定位到头节点位置
    while (p != NULL && p->m_destindex != p2index)
    {
        pf = p;
        p = p->m_next;
    }
    if (p == NULL)//没有边
        return;
    if(pf==NULL)//删除的是第一个边p,就把头指向第二个边
    {
        m_VerArr[p1index].m_list = p->m_next;
    }
    else//删除的是第二个及后面的边,就让第一个指向p的下一个
    {
        pf->m_next = p->m_next;
    }
    delete p;
    pf = NULL;
    //删除v2到v1
    p = m_VerArr[p2index].m_list;//p指向v2
    while (p->m_destindex != p1index)
    {
        pf = p;
        p = p->m_next;
    }
    //1.第一个
    if (pf == NULL)
        m_VerArr[p2index].m_list = p->m_next;
    //2.第二个以后
    else
        pf->m_next = p->m_next;
    delete p;
}

//删顶点,删除顶点不仅需要删除某一顶点还需要删除和他相连的边
void Graph::DeleteVertex(char v)//删除顶点v
{
    int vindex = GetVertexIndex(v);
    if (vindex == -1)
        return;
    Edge* p = m_VerArr[vindex].m_list;
    char destVerTex;
    while (p != NULL)//先把顶点内边删除完毕
    {
        destVerTex = m_VerArr[p->m_destindex].m_value;
        DeleteEdge(v, destVerTex);
        p = m_VerArr[vindex].m_list;
    }
    //然后开始删除顶点
    //顶点是个一维数组,普通删除是移动进行替换,但是此处采用的方式是覆盖,用最后一个顶点覆盖待删除顶点的所有信息
    m_NumVertex--;//顶点个数先--
    m_VerArr[vindex].m_value = m_VerArr[m_NumVertex].m_value;
    m_VerArr[vindex].m_list = m_VerArr[m_NumVertex].m_list;

    //在其他节点内对删除结点的边进行下标替换为最后一个结点的下标
    p = m_VerArr[vindex].m_list;//p是记录最后一个结点对应的链内下标
    Edge* q = NULL;//q记录新结点对应链内下标
    while (p != NULL)
    {
        int k = p->m_destindex;//p内找到结点下标a
        q = m_VerArr[k].m_list;//q记录新结点对应链内下标
        while (q != NULL)//在q内查找这个a下标
        {
            if (q->m_destindex == m_NumVertex)//找到了就把a结点的值改为p所在的结点(最后挪上来的结点)
            {
                q->m_destindex = vindex;
                break;
            }
            else
                q = q->m_next;
        }
        p = p->m_next;
    }
}

void Graph::BFS(char v)
{
    queue<int>qq;
    bool* visited = new bool[m_NumVertex];
    int front;
    Edge* p = NULL;
    for (int i = 0; i < m_NumVertex; i++)
    {
        visited[i] = false;
    }
    int vindex = GetVertexIndex(v);
    if (vindex == -1)
    {
        return;//说明不存在该顶点
    }
    qq.push(vindex);
    cout << v << " ";
    visited[vindex] = true;
    while (!qq.empty())//当队列不空,获取队头元素出队
    {
        front = qq.front;
        qq.pop();
        //访问队头元素的邻接顶点
        p = m_Vertex[vindex].m_list;//让p指向队头元素的邻接表,用邻接表访问邻接结点
        while (p)//有邻接顶点
        {
            if (!visited[p->m_destindex])//未被访问
            {
                cout << m_VerArr[p->m_destindex].m_value;//输出该结点的值
                visited[p->m_destindex] = true;
                qq.push(p->m_destindex);
            }
            p = p->m_next;
        }
    }
    delete[]visited;
    visited = NULL;

}

void Graph::DFS(char v)
{
    bool* visited = new bool[m_NumVertex];
    for (int i = 0; i < m_NumVertex; i++)
    {
        visited[i] = false;
    }
    int vindex = GetVertexIndex(v);
    if (vindex == -1)
        return;
    DFS(vindex,visited);//递归调用
    delete[]visited;
    visited = NULL;
}

void Graph::DFS(int v, bool* visited)//递归
{
    cout << m_VerArr[v].m_value << " ";
    visited[v] = true;
    Edge* p = m_VerArr[v].m_list;//p指向邻接表
    while (p)
    {
        if (!visited[p->m_destindex])
            DFS(p->m_destindex);
        p = p->m_next;
    }
}

int main()
{
    Graph g;
    g.InsertVertex('a');
    g.InsertVertex('b');
    g.InsertVertex('c');
    g.InsertVertex('d');
    g.InsertEdge('a', 'b');
    g.InsertEdge('a', 'c');
    g.InsertEdge('a', 'd');
    g.InsertEdge('b', 'c');
    g.InsertEdge('c', 'd');
    g.ShowGraph();
    g.BFS('a');//从a开始调用
    g.DFS('a');
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值