<图>深度优先遍历list

图的遍历的两种方法
  广度优先(Breadth First Serrch)
    像水波一样一层一层由内到外扩散访问
    核心思想:先被访问的顶点,其邻接点也先被访问 ??
    队列的思想:先进先出 notice:
  深度优先(DFS)
    一条路走到黑,如果走不通就返回一开始的位置走下一条路,
    如果走得通就走出去了,其他的路也不管了
    核心思想:后被访问(出栈)的顶点,其第一个邻接点先被访问(出栈) ??
    栈的思想:后进先出、后出 notice:

eg:
     b
   ↗   ↘
  a  →  c  5个顶点,7条边
  ↓  ↙  ↓
  e  ←  d
  Vex[] = a b c d e    a:0 b:1 c:2 d:3 e:4

    顶(出发)点表  邻接点(进入点)表:逆序
    [a|p_first] [4|p_next] [2|p_next] [1|p_next] NULL     a→e a→c a→b
              ↓→↑        ↓→↑        ↓→↑        ↓→↑
    [b|p_first] [2|p_next] NULL                           b→c
              ↓→↑        ↓→↑
    [c|p_first] [4|p_next] [3|p_next] NULL                c→e c→d
              ↓→↑        ↓→↑        ↓→↑
    [d|p_first] [4|p_next] NULL                           d→e
              ↓→↑        ↓→↑
    [e|p_first] NULL                                      e→N
              ↓→↑

基于邻接矩阵的深度优先算法:
  找到当前顶点的[没有被访问过]的[最近]邻接点入栈,「入栈的过程」 == 「深度优先遍历的过程」
  从a走到e,发现走不通了e没用了出栈,返回到原点a,走另一条路a→c,
  c→e,e已经被标记过了,走c→d,d入栈,d之后没有了,d出栈
  c之后没有了,c出栈,走a→b,b入栈,b之后没有了,b出栈,a之后没有了,a出栈,栈空
  入栈顺序:a、e、c、d、b    每一次入栈都要标记
    |   |     |   |     |   |     |   |     |   |←         
    |   |     |   |←    |   |     |   |←    | d |         
    |   |←    | e |     |   |←    | c |     | c |          
    |_a_|     |_a_|     |_a_|     |_a_|     |_a_|          

    |   |     |   |     |   |     |   |     |   |
    |   |←    |   |     |   |←    |   |     |   |
    | c |     |   |←    | b |     |   |←    |   |
    |_a_|     |_a_|     |_a_|     |_a_|     |___|←

  过程总结:
    step1 创建一个数组用于表示顶点是否被访问过
    step2 创建一个空栈
    step3 从图的起点(下标为0)出发,标记访问过,将顶点(下标)压入栈
    step4 判断栈是否为空,若不为空则继续访问,否则结束
    step5 顶点(头部)出栈后,依次访问该顶点[未被访问过的][最近邻接点],标记并入队列
    step6 返回4

考虑非连通
     b
   ↗   ↘
  a  →  c  f → g
  ↓  ↙  ↓
  e  ←  d
#include <iostream>
#include "directed_list.h"
using namespace std;


int main()
{
	struct ALG_Graph* d_graph;

	d_graph = Create_ALG_Graph();

    Show_ALG_Graph(d_graph);

    cout << "深度优先搜索遍历邻接表:"<< endl;
    // 只适用于连通图
    DFS_ALG(d_graph);

    // 适用于连通与非连通图
    DFS_ALG_NotConnect(d_graph);

    return 0;
}

directed_list.cpp

#include <iostream>
#include "directed_list.h"
#include "stack.h"
using namespace std;


struct ALG_Graph* Create_ALG_Graph(void)
{
    int i,j;
    char u, v;
    struct ALG_Graph* graph;

    // 申请内存空间,结构体多大申请多大,强制类型转换
    graph = (struct ALG_Graph *)malloc(sizeof(struct ALG_Graph));

    cout << "请输入顶点的个数: ";
    cin >> graph->vex_num;

    cout << "请输入边的个数: ";
    cin >> graph->edge_num;

    cout << "请输入顶点信息: " << endl;

    for(i = 0; i < graph->vex_num; i++)
    {
        // 捕获每个顶点信息:a b c...
        cin >> graph->Vex[i].node;
    }

    for(i = 0; i < graph->vex_num; i++)
    {
        // notice: 顶点表全部初始化为空指针
        graph->Vex[i].first = NULL;
    }

    // 一条边对应一个邻接节点
    while(graph->edge_num--)
    {
        cout << "请输入通过边连接起来的顶点:" << endl;
        cin >> u;
        cin >> v;

        // 到graph中找到字符u,所对应的索引i(出发点的索引号)、j(进入点的索引号)
        i = search_vex(graph, u);
        j = search_vex(graph, v);

        // 如果找到了
        if(i != -1 && j != -1)
        {
            // notice: 构建邻接点表(形成单链表),入参:顶点表的顶点、出发点的索引号、进入点的索引号
            create_adjNode_list(graph, i, j);
        }
        else// 如果没有找到
        {
            cout << "你输入的顶点信息是错的,请再次输入" << endl;
            graph->edge_num++;
        }
    }

    return graph;
}


int search_vex(struct ALG_Graph* graph, char c)
{
    int i;
    // 有多少个顶点循环多少次
    for(i = 0; i < graph->vex_num; i++)
    {
        if(c == graph->Vex[i].node)
            return i;
    }
    return -1;
}

/*
输入前:
[a|p_first] NULL
          ↓→↑

输入   i  j

a b   0  1  [a|p_first] [1|p_next] NULL
                      ↓→↑        ↓→↑

a c   0  2  [a|p_first] [2|p_next] [1|p_next] NULL
                      ↓→↑        ↓→↑        ↓→↑

a e   0  4  [a|p_first] [4|p_next] [2|p_next] [1|p_next] NULL
                      ↓→↑        ↓→↑        ↓→↑        ↓→↑
最终:
    顶点表       邻接点表
    [a|p_first] [4|p_next] [2|p_next] [1|p_next] NULL
              ↓→↑        ↓→↑        ↓→↑        ↓→↑
*/

// 入参:顶点表的顶点、出发点的索引号、进入点的索引号 i --> j
void create_adjNode_list(struct ALG_Graph* graph, int i, int j)
{
    // 创建邻接节点
    struct AdjNode* s = (struct AdjNode*)malloc(sizeof(struct AdjNode));

    // 邻接点的下标是进入点索引
    s->index = j;

    //    [1|next] NULL    [2|p_next] [1|p_next] NULL
    //           ↓→↑                ↓→↑        ↓→↑
    s->next = graph->Vex[i].first;

    /*
            ↑→ [2|p_next] →↓
    [a|first]              [1|next] NULL
            ↓→ → → X → → → ↑      ↓→↑
    */

    // [a|first] [1|next] NULL   [a|p_first] [2|p_next] [1|p_next] NULL
    //         ↓→↑      ↓→↑                ↓→↑        ↓→↑         ↓→↑
    graph->Vex[i].first = s;
}


void Show_ALG_Graph(struct ALG_Graph * graph)
{
    int i,j;
    // 邻接点指针
    struct AdjNode* temp;
    cout << "顶点表\t邻接点表"<< endl;
    for(i = 0; i < graph->vex_num; i++)
    {
        // 顶点信息
        cout << graph->Vex[i].node << "\t";
        temp = graph->Vex[i].first;
        // 显示单链
        while(temp != NULL)
        {
            // 邻接表索引
            cout << " " << temp->index;
            // 更新
            temp = temp->next;
        }
        cout << endl;
    }

}



// 深度优先遍历邻接表,连通
void DFS_ALG(struct ALG_Graph* graph)
{
    int u,n;
    // 邻接点表中的邻接点
    struct AdjNode* p;

    // step1 创建一个数组用于表示顶点是否被访问过
    int visited[MAX] = {0};

    // step3 从图的起点(下标为0)出发,标记访问过,将顶点(下标)入队列
    visited[0] = 1;
    push(0);
    // 「入栈的过程」 == 「深度优先遍历的过程」
    cout << graph->Vex[0].node;

    // step4 判断如果队列是否为空,若是则继续访问,否则结束
    while(!isempty())
    {
        u = stack[top-1];
        p = graph->Vex[u].first;// a的第一个邻接点e

        // step5 顶点(头部)出队列后,判断p_first是否为空,如果不为空则继续
        // 依次访问该顶点的 [未被访问过的][最近邻接点],如果未被标记并入队列
        while(p)
        {
            n = p->index;
            // 如果当前顶点没有被标记过
            if(visited[n] == 0)
            {
                visited[n] = 1;
                // 下标入栈
                push(n);
                //「入栈的过程」 == 「深度优先遍历的过程」
                cout << " "<< graph->Vex[n].node;// e、c
                // 更新为当前节点的最近邻接点
                p = graph->Vex[n].first;
            }
            else// 如果当前顶点被标记过
                p = p->next;// 指向c
        }
        // 一条路走不桶,则出栈
        pop();

    }
    cout << endl;
}


// 深度优先遍历邻接表,非连通
void DFS_ALG_NotConnect(struct ALG_Graph* graph)
{
    int u,n;
    // 邻接点表中的邻接点
    struct AdjNode* p;

    // step1 创建一个数组用于表示顶点是否被访问过
    int visited[MAX] = {0};


    // 防止非连通
    for(int i = 0; i < graph->vex_num; i++)
    {   
        // 如果该顶点没有被访问过则
        if(visited[i] == 0)
        {
            // 起始点
            cout << graph->Vex[i].node;// a、....f
            // step3 从图的起点(下标为0)出发,标记访问过,将顶点(下标)入队列
            visited[i] = 1;
            push(i);

            // step4 判断如果队列是否为空,若是则继续访问,否则结束
            while(!isempty())
            {
                // step5 顶点(头部)出队列后,判断p_first是否为空,如果不为空则继续
                // 依次访问该顶点的 [未被访问过的][邻接点],如果未被标记并入队列
                
                u = stack[top-1];
                p = graph->Vex[u].first;// a的第一个邻接点e

                // 若顶点的邻接点不为空
                while(p)
                {
                    n = p->index;
                    // 如果没有被标记过
                    if(visited[n] == 0)
                    {
                        visited[n] = 1;
                        // 下标入栈
                        push(n);
                        cout << " "<< graph->Vex[n].node;// e、c
                        p = graph->Vex[n].first;
                    }
                    else
                        // 更新:从a->e,更新为a->c
                        p = p->next;// 指向c

                }
                // 一条路走不桶,则出栈
                pop();
                
            }

        }

    }
    cout << endl;

}

directed_list.h

#ifndef __directed_list_h__
#define __directed_list_h__


#define MAX 100
// 邻接点表(链表)中的邻接点
struct AdjNode
{
    // [邻接点的下标|指向下一个邻接点的指针(逆序)]
    int index;
    struct AdjNode* next;
};

// 顶点表(链表)中的顶点
struct VexNode
{
    // [顶点的信息|该顶点指向第一个邻接点的指针(逆序)]
    char node;
    struct AdjNode* first;
};


struct ALG_Graph
{
	// 顶点的个数,边的个数
	int vex_num, edge_num;

	// 一维数组储存顶点的信息 --> 顶点表
	// 二维矩阵储存顶点和顶点之间的邻接关系 --> 邻接点表

    // 数组中的每个元素都是一个结构体对象(一个顶点的单链)
    struct VexNode Vex[MAX];

};

struct ALG_Graph* Create_ALG_Graph(void);
int search_vex(struct ALG_Graph* graph, char c);
void create_adjNode_list(struct ALG_Graph* graph, int i, int j);
void Show_ALG_Graph(struct ALG_Graph * graph);
void DFS_ALG(struct ALG_Graph* graph);
void DFS_ALG_NotConnect(struct ALG_Graph* graph);

#endif

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值