浅谈【数据结构】图-图的遍历

目录

1、图的遍历

2、深度优先搜索算法

3、广度优先搜索算法


谢谢帅气美丽且优秀的你看完我的文章还要点赞、收藏加关注

没错,说的就是你,不用再怀疑!!!

希望我的文章内容能对你有帮助,一起努力吧!!!


1、图的遍历

图的遍历是对树的遍历的推广,是按照一种规划(或者说是一种次序)访问图中各顶点一次,并且只能 访问一次,亦或者是将网状结构按照某种规划进行线性化。

对于图的遍历通常有两种方式:

  • 广度优先搜索算法(Breath First search)BFS
  • 深度优先搜索算法(Depth First search)DFS

两者是现代人工智能AI的基础。

2、深度优先搜索算法

深度优先搜索算法(Depth First search)DFS

设初始化的时候,图中各个顶点均为被访问过。从图中某个顶点(V0)出发,访问V0,然后搜索V0的 邻接顶点Vi,再以Vi为基础访问Vi的邻接顶点(依次下去...)(深度优先)。若某个顶点没有邻接顶点 (邻接顶点均被访问完毕),则回溯到它上一个顶点,然后再从它的上一个顶点开始继续进行邻接顶点 的访问,直到所有的顶点都被访问完毕。

***DFS示例代码***

#include <iostream>
#include <cstring>

// 关系类型
typedef struct relation
{
    int index; // 下标
    int weight; // 权值
    struct relation *next; // 下一个关系的顶点的下标指针
}Relation_t;

// 顶点类型
typedef struct 
{
    std::string data; // 顶点数据
    Relation_t *first; // 该顶点的关系集
}Vertex_t;


// 当前顶点数
int current_count = 0;

/*
    @brief  创建一个图:邻接表
    @param  count 该图的最大顶点数量 
    @return 成功返回创建好的图指针
*/
Vertex_t *creatGraph(int count)
{
    // 申请空间
    Vertex_t *graph = new Vertex_t[count];

    // 初始化
    memset(graph,0,sizeof(Vertex_t)*count);

    std::cout << "请输入顶点数据空格分开(“结束”输入):";
    // 接受顶点

    while(1)
    {
        std::string data = "结束";
        std::cin >> data;
        if(data == "结束")
            break;

        if(current_count == count)
            break;

        // 新增顶点位置
        graph[current_count].data  = data;
        graph[current_count].first = nullptr;

        current_count++;
    }

    // 增加关系
    while(1)
    {
        std::cout << "请输入顶点关系(结束 结束 -1):";

        // 出发顶点和终止顶点 权值
        std::string start;
        std::string end;
        int data;
        std::cin >> start >> end >> data;

        if(start=="结束"||end=="结束"||data == -1)
            break;

        // 存储关系
        // 获取start和end在图数组的什么位置
        int index_s = 0,index_e = 0;
        for(;index_s < current_count;index_s++)
            if(graph[index_s].data == start)
                break;
        for(;index_e < current_count;index_e++)
            if(graph[index_e].data == end)
                break;

        // 两个顶点的下标找到了
        if(index_s == current_count||index_e == current_count)
            continue;
        
        // 添加关系
        Relation_t *rt = new Relation_t;
        rt->index = index_e;
        rt->weight = data;
        rt->next = nullptr;

        // 当至少存在出度顶点的时候
        if(graph[index_s].first)
        {
            Relation_t *rt_ptr = graph[index_s].first;
            while(rt_ptr->next)
                rt_ptr = rt_ptr->next;
            
            // 存进关系链表
            rt_ptr->next = rt;
        }
        else{ // 一个出度结点都没有的时候
            graph[index_s].first = rt;
        }
    }

    return graph;
}

void printrelation(Vertex_t *graph)
{
    if(!graph)
        std::cout << "空图" << std::endl;
    
    for(int count_v = 0;count_v < current_count;count_v++)
    {
        std::cout << "顶点<"<< graph[count_v].data <<">:";
        
        Relation_t *rt_ptr = graph[count_v].first;
        while(rt_ptr)
        {
            std::cout<< "<"<< graph[count_v].data <<","<< 
            graph[rt_ptr->index].data <<">" 
            << "("<<rt_ptr->weight<<")";
        
            rt_ptr = rt_ptr->next;
        }
        std::cout << std::endl;
    }
}


// 计算下标
int getIndex(Vertex_t *graph,std::string vertex_v)
{
    for(int index = 0;index < current_count;index++)
    {
        if(vertex_v == (graph[index]).data)
            return index;
    }
    return -1;
}



/*
    逻辑:
        设初始化的时候,图中各个顶点均为被访问过。
        从图中某个顶点(V0)出发,访问V0,然后搜索V0的邻接顶点Vi,再以Vi为基础访问Vi的邻接顶点(依次下去...)(深度优先)。
        若某个顶点没有邻接顶点(邻接顶点均被访问完毕),
        则回溯到它上一个顶点,然后再从它的上一个顶点开始继续进行邻接顶点的访问,直到所有的顶点都被访问完毕。
    @brief 深度优先搜索算法
    @param graph 需要进行深度优先搜索的图指针
*/
void DFS(Vertex_t *graph,std::string v0)
{
    int v0_pos = getIndex(graph,v0);
    if(v0_pos == -1)
        return;

    // 标志位数组,且初始化所有顶点都为未被访问
    static bool *flags=new bool[current_count];

    // 访问V0
    std::cout << graph[v0_pos].data << " ";
    flags[v0_pos] = true;

    Relation_t *currnet_relation = graph[v0_pos].first;

    while(currnet_relation)
    {
        // 递归下去进行访问
        if(flags[currnet_relation->index] == false)
            DFS(graph,graph[currnet_relation->index].data);

        // 递归结束返回,再次访问下一个邻接点
        currnet_relation = currnet_relation->next;
    }

    std::cout << std::endl;
}



int main()
{
    Vertex_t *graph = creatGraph(10);

    DFS(graph,"A");

    delete []graph;

    return 0;
}

3、广度优先搜索算法

广度优先搜索算法(Breath First search)BFS

类似于树的层次遍历,初始化的时候,图中的各项顶点均未被访问,从图某个顶点开始(V0)依次的访 问V0的各个邻接点(广度优先)

然后分别冲这些被访问过的顶点出发,仍然按照广度优先的策略访问其他的顶点...直到所有能访问的顶 点均被访问完毕。

***BFS示例代码***

#include <iostream>
#include <cstring>
#include <queue>

// 关系类型
typedef struct relation
{
    int index; // 下标
    int weight; // 权值
    struct relation *next; // 下一个关系的顶点的下标指针
}Relation_t;

// 顶点类型
typedef struct 
{
    std::string data; // 顶点数据
    Relation_t *first; // 该顶点的关系集
}Vertex_t;


// 当前顶点数
int current_count = 0;

/*
    @brief  创建一个图:邻接表
    @param  count 该图的最大顶点数量 
    @return 成功返回创建好的图指针
*/
Vertex_t *creatGraph(int count)
{
    // 申请空间
    Vertex_t *graph = new Vertex_t[count];

    // 初始化
    memset(graph,0,sizeof(Vertex_t)*count);

    std::cout << "请输入顶点数据空格分开(“结束”输入):";
    // 接受顶点

    while(1)
    {
        std::string data = "结束";
        std::cin >> data;
        if(data == "结束")
            break;

        if(current_count == count)
            break;

        // 新增顶点位置
        graph[current_count].data  = data;
        graph[current_count].first = nullptr;

        current_count++;
    }

    // 增加关系
    while(1)
    {
        std::cout << "请输入顶点关系(结束 结束 -1):";

        // 出发顶点和终止顶点 权值
        std::string start;
        std::string end;
        int data;
        std::cin >> start >> end >> data;

        if(start=="结束"||end=="结束"||data == -1)
            break;

        // 存储关系
        // 获取start和end在图数组的什么位置
        int index_s = 0,index_e = 0;
        for(;index_s < current_count;index_s++)
            if(graph[index_s].data == start)
                break;
        for(;index_e < current_count;index_e++)
            if(graph[index_e].data == end)
                break;

        // 两个顶点的下标找到了
        if(index_s == current_count||index_e == current_count)
            continue;
        
        // 添加关系
        Relation_t *rt = new Relation_t;
        rt->index = index_e;
        rt->weight = data;
        rt->next = nullptr;

        // 当至少存在出度顶点的时候
        if(graph[index_s].first)
        {
            Relation_t *rt_ptr = graph[index_s].first;
            while(rt_ptr->next)
                rt_ptr = rt_ptr->next;
            
            // 存进关系链表
            rt_ptr->next = rt;
        }
        else{ // 一个出度结点都没有的时候
            graph[index_s].first = rt;
        }
    }

    return graph;
}

void printrelation(Vertex_t *graph)
{
    if(!graph)
        std::cout << "空图" << std::endl;
    
    for(int count_v = 0;count_v < current_count;count_v++)
    {
        std::cout << "顶点<"<< graph[count_v].data <<">:";
        
        Relation_t *rt_ptr = graph[count_v].first;
        while(rt_ptr)
        {
            std::cout<< "<"<< graph[count_v].data <<","<< 
            graph[rt_ptr->index].data <<">" 
            << "("<<rt_ptr->weight<<")";
        
            rt_ptr = rt_ptr->next;
        }
        std::cout << std::endl;
    }
}


// 计算下标
int getIndex(Vertex_t *graph,std::string vertex_v)
{
    for(int index = 0;index < current_count;index++)
    {
        if(vertex_v == (graph[index]).data)
            return index;
    }
    return -1;
}



/*
    逻辑:
        类似于树的层次遍历,初始化的时候,图中的各项顶点均未被访问,
        从图某个顶点开始(V0)依次的访问V0的各个邻接点(广度优先)
        然后分别冲这些被访问过的顶点出发,仍然按照广度优先的策略访问其他的顶点...直到所有能访问的顶点均被访问完毕。
    @brief 广度优先搜索算法
    @param graph 需要进行广度优先搜索的图指针
*/
void BFS(Vertex_t *graph,std::string v0)
{
    int v0_pos = getIndex(graph,v0);
    if(v0_pos == -1)
        return;

    // 搞个队列
    std::queue<int> q;

    // 入队V0
    q.push(v0_pos);

    // 标志位数组,且初始化所有顶点都为未被访问
    static bool *flags=new bool[current_count];

    // 访问V0
    flags[v0_pos] = true;

    int current_pos = v0_pos;

    while(q.size())
    {
        Relation_t *currnet_relation=graph[current_pos].first;

        // 当前关系是否存在 循环的作用:是将该顶点的所有边都入队
        while(currnet_relation)
        {
            // 是否被访问过
            if(flags[currnet_relation->index] == false)
            {
                q.push(currnet_relation->index);
                flags[currnet_relation->index] = true;
            }

            // 递归结束返回,再次访问下一个邻接点
            currnet_relation = currnet_relation->next;
        }

        // 出队,打印、标记
        current_pos = q.front();
        q.pop();

        std::cout << graph[current_pos].data << " ";
        
    }

    std::cout << std::endl;
}



int main()
{
    Vertex_t *graph = creatGraph(10);

    BFS(graph,"A");

    delete []graph;

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值