数据结构(五)图---图的两种遍历(深度优先和广度优先)

从图的某一顶点出发访遍其余顶点,且使每一个顶点仅被访问一次,这一过程就叫做图的遍历

一:深度优先遍历(邻接矩阵实现)

(一)定义

假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点(未连通),则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。
图的深度优先遍历类似于树的前序遍历。采用的搜索方法的特点是尽可能先对纵深方向进行搜索。这种搜索方法称为深度优先搜索(Depth-First Search)。相应地,用此方法遍历图就很自然地称之为图的深度优先遍历

(二)实现思路

1)访问顶点v;
(2)从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
(3)重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。

(三)递归实现伪代码

1)访问顶点v;visited[v]=1//算法执行前visited[n]=02)w=顶点v的第一个邻接点;
(3while(w存在)  
           if(w未被访问)
                   从顶点w出发递归执行该算法; 
           w=顶点v的下一个邻接点;

(四)非递归实现伪代码

1)栈S初始化;visited[n]=0;
(2)访问顶点v;visited[v]=1;顶点v入栈S
(3while(栈S非空)
            x=栈S的顶元素(不出栈);
            if(存在并找到未被访问的x的邻接点w)
                    访问w;visited[w]=1;
                    w进栈;
            else
                     x出栈;

(五)代码实现(递归+非递归)

头文件

《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

#pragma once
#ifndef _STACK_H
#define _STACK_H
#include <stdio.h>
#include <stdlib.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 100

typedef int ElemType;
typedef int Status;

typedef struct  
{
    ElemType data[MAXSIZE];
    int top;
}Stack;

Status InitStack(Stack* S);
Status Push(Stack* S, ElemType e);
Status Pop(Stack* S, ElemType* e);
Status EmptyStack(Stack S);
ElemType getTop(Stack S);

#endif

stack.h
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

#pragma once
#ifndef _SEARCH_H
#define _SEARCH_H

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define MAXVEX 100    //最大顶点数
#define INFINITY 0    //用0表示∞

typedef char VertexType;    //顶点类型,字符型A,B,C,D...
typedef int EdgeType;    //边上权值类型10,15,...

typedef struct
{
    VertexType vers[MAXVEX];    //顶点表
    EdgeType arc[MAXVEX][MAXVEX];    //邻接矩阵,可看作边表
    int numVertexes, numEdges;    //图中当前的顶点数和边数
}MGraph;

#endif

01search.h

源文件

《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

#include "stack.h"

Status InitStack(Stack* S)
{
    if (!S)
        return ERROR;
    S->top = -1;
    return OK;
}

Status Push(Stack* S, ElemType e)
{
    if (!S)
        return ERROR;
    S->data[++S->top] = e;
    return OK;
}

Status Pop(Stack* S, ElemType* e)
{
    if (!S || !e)
        return ERROR;
    *e = S->data[S->top--];
    return OK;
}

Status EmptyStack(Stack S)
{
    if (S.top != -1)
        return FALSE;
    return TRUE;
}

ElemType getTop(Stack S)
{
    if (S.top == -1)
        return NULL;
    return S.data[S.top];
}

stack.c

#include "01search.h"
#include "stack.h"


bool visited[MAXVEX];    //访问标志的数组

void CreateMGraph(MGraph* G);  //创建邻接矩阵

void DFSTraverse(MGraph M);  //深度优先遍历前会进行初始化
void DFS(MGraph M, int i);    //邻接矩阵深度优先算法
void DFSInter(MGraph M, int i);    //邻接矩阵深度非递归优先算法
void showGraph(MGraph G);  //显示矩阵

《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

void CreateMGraph(MGraph* G)
{
    int i, j, k, w;
    //     printf("please input number of vertex and edge:\n");
    //     scanf("%d,%d", &G->numVertexes, &G->numEdges);    //输入顶点数和边数
    //     getchar();    //可以获取回车符
    //     for (i = 0; i < G->numVertexes; i++)    //读入顶点信息,建立顶点表
    //         scanf("%c", &G->vers[i]);

    G->numVertexes = 9;
    G->numEdges = 15;
    //读入顶点信息
    G->vers[0] = 'A';
    G->vers[1] = 'B';
    G->vers[2] = 'C';
    G->vers[3] = 'D';
    G->vers[4] = 'E';
    G->vers[5] = 'F';
    G->vers[6] = 'G';
    G->vers[7] = 'H';
    G->vers[8] = 'I';

    //getchar();    //可以获取回车符
    for (i = 0; i < G->numVertexes; i++)
        for (j = 0; j < G->numVertexes; j++)
            G->arc[i][j] = INFINITY;    //邻接矩阵初始化

    G->arc[0][1] = 1;
    G->arc[0][5] = 1;
    G->arc[1][2] = 1;
    G->arc[1][8] = 1;
    G->arc[1][6] = 1;
    G->arc[2][3] = 1;
    G->arc[2][8] = 1;
    G->arc[3][4] = 1;
    G->arc[3][7] = 1;
    G->arc[3][6] = 1;
    G->arc[3][8] = 1;
    G->arc[4][5] = 1;
    G->arc[4][7] = 1;
    G->arc[5][6] = 1;
    G->arc[6][7] = 1;

    for (k = 0; k < G->numVertexes; k++)    //读入numEdges条边,建立邻接矩阵
    {
        for (i = k; i < G->numVertexes; i++)
        {
            G->arc[i][k] = G->arc[k][i];    //因为是无向图,所有是对称矩阵
        }
    }
}

CreateMGraph创建邻接矩阵
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

void showGraph(MGraph G)
{
    for (int i = 0; i < G.numVertexes; i++)
    {
        for (int j = 0; j < G.numVertexes; j++)
            printf("%2d", G.arc[i][j]);
        printf("\n");
    }
}

showGraph显示邻接矩阵
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

void DFSTraverse(MGraph M)
{
    int i;
    for (i = 0; i < M.numVertexes; i++)
        visited[i] = false;    //初始化所有顶点状态都是未访问过的未访问状态

    for (i = 0; i < M.numVertexes; i++)
        if (!visited[i])    //对未访问的顶点调用DFS,若是连通图,只会调用一次
            DFSInter(M, i);
            //DFS(M, i);
}

DFSTraverse深度优先前的初始化和调用
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

void DFS(MGraph M, int i)    //邻接矩阵深度优先算法
{
    int j;
    visited[i] = true;    //访问后我们会一直向后退,去访问其他结点,不会再访问这个结点,所有我们不需要再置为false
    printf("%c", M.vers[i]);
    for (j = 0; j < M.numVertexes; j++)
        if (M.arc[i][j] == 1 && !visited[j])    //因为邻接矩阵是对称的,所以当我们访问到下半部时,有一些结点时前面已经访问过的,我们就不要重复了
            DFS(M, j);    //对未访问过的邻接顶点递归调用
}

DFS深度优先递归实现
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

void DFSInter(MGraph M, int i)    //邻接矩阵深度非递归优先算法
{
    int j,flag;
    Stack s;
    InitStack(&s);

    visited[i] = true;    //访问后我们会一直向后退,去访问其他结点,不会再访问这个结点,所有我们不需要再置为false
    printf("%c", M.vers[i]);
    Push(&s, i);
    while (!EmptyStack(s))
    {
        i = getTop(s);
        for (j = 0; j < M.numVertexes; j++)
            if (M.arc[i][j] == 1 && !visited[j])    //因为邻接矩阵是对称的,所以当我们访问到下半部时,有一些结点时前面已经访问过的,我们就不要重复了
            {
                visited[j] = true;
                printf("%c", M.vers[j]);
                flag = 1;
                Push(&s, j);
                break;
            }
        if (!flag)
            Pop(&s, &i);
        flag = 0;
    }
}

DFSInter深度优先非递归实现

int main()
{
    MGraph MG;
    CreateMGraph(&MG);
    showGraph(MG);
    DFSTraverse(MG);
    system("pause");
    return 0;
}

《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

注意:深度优先遍历的方法不止一种,结果也有不同种,当我们使用方法一致时,结果是一样的,无论递归还是迭代

(六)应用:马踏棋盘

规则

8*8方格,将马放在任意位置,按照马走日,进行移动,要求一个方格进入一次,最后使得马走遍64个方格

《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

回溯法

一条路走到黑,碰壁了再回来一条路走。可以与递归很好搭配,也可以和深度优先搜索一起

哈密尔顿路径

是指结果图G中的每个顶点,且只经过一次的一条轨迹。如果这条轨迹是一个闭合的路径(从起点出发不重复的遍历所有点后仍能回到起始点),那么这条路径叫做哈密尔顿回路

代码实现

《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define X 8
#define Y 8

int chess[X][Y];

//找到x,y位置的下一个可走位置,并返回,其中count代表了我们尝试了多少次,一个有八种走法,所有count从0-7
//按照棋盘显示的来走
int nextxy(int* x, int* y, int count)
{
    switch (count)
    {
    case 0:
        if ((*x + 2) < X && (*y - 1) >= 0 && !chess[*x + 2][*y - 1])
        {
            *x += 2;
            *y -= 1;
            return 1;
        }
        break;
    case 1:
        if ((*x + 2) < X && (*y + 1) < Y && !chess[*x + 2][*y + 1])
        {
            *x += 2;
            *y += 1;
            return 1;
        }
        break;
    case 2:
        if ((*x + 1) < X && (*y - 2) >= 0 && !chess[*x + 1][*y - 2])
        {
            *x += 1;
            *y -= 2;
            return 1;
        }
        break;
    case 3:
        if ((*x + 1) < X && (*y + 2) < Y && !chess[*x + 1][*y + 2])
        {
            *x += 1;
            *y += 2;
            return 1;
        }
        break;
    case 4:
        if ((*x - 2) >= 0 && (*y - 1) >= 0 && !chess[*x - 2][*y - 1])
        {
            *x -= 2;
            *y -= 1;
            return 1;
        }
        break;
    case 5:
        if ((*x - 2) >= 0 && (*y + 1) < Y && !chess[*x - 2][*y + 1])
        {
            *x -= 2;
            *y += 1;
            return 1;
        }
        break;
    case 6:
        if ((*x - 1) >= 0 && (*y - 2) >= 0 && !chess[*x - 1][*y - 2])
        {
            *x -= 1;
            *y -= 2;
            return 1;
        }
        break;
    case 7:
        if ((*x - 1) >= 0 && (*y + 2) < Y && !chess[*x - 1][*y + 2])
        {
            *x -= 1;
            *y += 2;
            return 1;
        }
        break;
    default:
        break;
    }
    return 0;
}

void ShowChess()
{
    for (int i = 0; i < X;i++)
    {
        for (int j = 0; j < Y;j++)
        {
            printf("%5d", chess[i][j]);
        }
        printf("\n");
    }
}

//深度优先遍历棋盘
//(x,y)为位置坐标
//第一次调用为我们输入的参数
//之后就是递归进行
//tag代表我们在棋盘上走的正确步数
TravelChessBoard(int x, int y, int tag)
{
    int flag,count=0;
    int x1, y1;
    x1 = x;
    y1 = y;

    chess[x][y] = tag;

    if (tag==X*Y)
    {
        //打印棋盘
        ShowChess();
        return 1;
    }

    flag = nextxy(&x1, &y1, count);    //我们只找了其中一种走法,如果没有找到,我们下面需要去遍历其他走法
    while (++count < 8 && !flag)
    {
        flag = nextxy(&x1, &y1, count);
    }

    //找到路径了
    while (flag)    //我们对这个点周围的所有可以走的位置都要遍历一下
    {
        if (TravelChessBoard(x1, y1, tag + 1))
            return 1;
        //若是这条路走不通,我们需要继续换下一条路,上面的count代表我们走到第几条路
        x1 = x;
        y1 = y;
        flag = nextxy(&x1, &y1, count);
        while (++count < 8 && !flag)
        {
            flag = nextxy(&x1, &y1, count);
        }
    }

    //如果这个点各个方向都不行,我们就要换点了,先将这个点置为0
    if (0 == flag)
    {
        chess[x][y] = 0;    //因为这里要用到原来x,y,所以我们需要保留他
    }

    return 0;
}

int main()
{
    clock_t start, end;
    int i, j;

    start = clock();
    for (i = 0; i < X; i++)
        for (j = 0; j < Y; j++)
            chess[i][j] = 0;

    if (!TravelChessBoard(2, 0, 1))
        printf("find ways failure!\n");

    end = clock();
    printf("time speed:%f(ms)\n", (double)(end - start)/CLOCKS_PER_SEC);

    system("pause");
    return 0;
}

View Code

《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

二:广度优先遍历(邻接矩阵)

(一)定义

图的广度优先遍历BFS算法是一个分层搜索的过程,和树的层序遍历算法类同,它也需要一个队列以保持遍历过的顶点顺序,以便按出队的顺序再去访问这些顶点的邻接顶点。 
我们需要用到队列去实现广度优先遍历

(二)实现思路

1)顶点v入队列。

(2)当队列非空时则继续执行,否则算法结束。

(3)出队列取得队头顶点v;访问顶点v并标记顶点v已被访问。

(4)查找顶点v的第一个邻接顶点col。

(5)若v的邻接顶点col未被访问过的,则col入队列。

(6)继续查找顶点v的另一个新的邻接顶点col,转到步骤(5)。

        直到顶点v的所有未被访问过的邻接点处理完。转到步骤(2)。
广度优先遍历图是以顶点v为起始点,由近至远,依次访问和v有路径相通而且路径长度为1,2,……的顶点。为了使“先被访问顶点的邻接点”先于“后被访问顶点的邻接点”被访问,需设置队列存储访问的顶点。

(三)伪代码

1)初始化队列Q;visited[n]=0;

(2)访问顶点v;visited[v]=1;顶点v入队列Q;

(3while(队列Q非空)   

              v=队列Q的对头元素出队;

              w=顶点v的第一个邻接点;

             while(w存在) 

                     如果w未访问,则访问顶点w;

                     visited[w]=1;

                     顶点w入队列Q;

                     w=顶点v的下一个邻接点。

(四)代码实现

《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

#pragma once
#ifndef _QUEUE_H
#define _QUEUE_H

#include <stdio.h>
#include <stdlib.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 100

typedef int ElemType;
typedef int Status;

typedef struct _qNode
{
    ElemType data;
    struct _qNode* next;
}QNode,*QNodePtr;

typedef struct
{
    QNodePtr front,rear;    //队头队尾指针
}LinkQueue;

Status InitQueue(LinkQueue* Q);
Status EnQueue(LinkQueue* Q, ElemType e);
Status DeQueue(LinkQueue* Q, ElemType* e);
Status EmptyQueue(LinkQueue Q);
Status getHead(LinkQueue Q,ElemType* e);

#endif

queue.h
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

#include "queue.h"


Status InitQueue(LinkQueue* Q)
{
    if (!Q)
        return ERROR;
    Q->front = Q->rear = (QNodePtr)malloc(sizeof(QNode));
    if (!Q->front)
        return ERROR;
    Q->front->next = NULL;
    return OK;
}

Status EnQueue(LinkQueue* Q, ElemType e)
{
    //尾插法
    if (!Q)
        return ERROR;
    QNodePtr q = (QNodePtr)malloc(sizeof(QNode));
    if (!q)
        return ERROR;
    q->data = e;
    q->next = (*Q).rear->next;
    (*Q).rear->next = q;
    Q->rear = q;
    return OK;
}

Status DeQueue(LinkQueue* Q, ElemType* e)
{
    QNodePtr q;
    if (!Q || !e || EmptyQueue(*Q))
        return ERROR;
    q = Q->front->next;
    Q->front->next = q->next;
    *e = q->data;
    if (Q->rear == q)
        Q->rear = Q->front;
    free(q);
    return OK;
}

Status EmptyQueue(LinkQueue Q)
{
    if (!Q.front->next)
        return TRUE;
    return FALSE;
}

Status getHead(LinkQueue Q,ElemType* e)
{
    QNodePtr q;
    if (EmptyQueue(Q))
        return ERROR;
    q = Q.front->next;
    *e = q->data;
    return OK;
}

queue.c
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

void BFSTraverse(MGraph G)
{
    LinkQueue Q;
    int i,j,k;

    for (i = 0; i < G.numVertexes; i++)
        visited[i] = false;    //初始化所有顶点状态都是未访问过的未访问状态
    
    InitQueue(&Q);

    for (i = 0; i < G.numVertexes;i++)
    {
        if (!visited[i])    //若是未访问过的就处理
        {
            visited[i] = true;    //设置当前顶点被访问过了
            printf("%c", G.vers[i]);    //打印顶点
            EnQueue(&Q, i);    //将此顶点入队
            while (!EmptyQueue(Q))    //若当前顶点不为空
            {
                DeQueue(&Q, &k);    //出队,获取出队行的相关列
                for (j = 0; j < G.numVertexes;j++)    
                {
                    if (G.arc[k][j]==1&&!visited[j])    //若是该列未被访问
                    {
                        visited[j] = true;    //标记访问过
                        printf("%c", G.vers[j]);    //输出数据
                        EnQueue(&Q, j);    //将其入队
                    }
                }
            }
        }
    }
}

void BFSTraverse(MGraph G)广度优先实现

《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

三:邻接表实现深度优先和广度优先

队列和栈的实现代码如上面一致

《数据结构(五)图---图的两种遍历(深度优先和广度优先)》
《数据结构(五)图---图的两种遍历(深度优先和广度优先)》

#pragma once
#ifndef _SEARCH_H
#define _SEARCH_H

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define MAXVEX 100    //最大顶点数
#define INFINITY 0    //用0表示∞

typedef char VertexType;    //顶点类型,字符型A,B,C,D...
typedef int EdgeType;    //边上权值类型10,15,...

//邻接矩阵结构
typedef struct
{
    VertexType vers[MAXVEX];    //顶点表
    EdgeType arc[MAXVEX][MAXVEX];    //邻接矩阵,可看作边表
    int numVertexes, numEdges;    //图中当前的顶点数和边数
}MGraph;

//邻接表结构
//边表结点
typedef struct _EdgeNode
{
    int adjvex;    //存放邻接点
    struct _EdgeNode* next;    //指向下一个
}EdgeNode;

//顶点表结点
typedef struct _VertexNode
{
    VertexType data;    //顶点域,存储顶点信息
    EdgeNode* fisrtedge;    //边表头指针
}VertexNode, AdjList[MAXVEX];

//邻接表指针
typedef struct
{
    AdjList adjList;    //邻接表数组
    int numVertexes, numEdges;    //图中所存储的顶点数和边表数
}GraphAdjList;

#endif

01search.h

#include "01search.h"
#include "stack.h"
#include "queue.h"


bool visited[MAXVEX];    //访问标志的数组

void CreateMGraph(MGraph* G);
void CreateALGraph(MGraph G, GraphAdjList *GL);//利用邻接矩阵构建邻接表

void DFSTraverse(GraphAdjList M);
void DFS(GraphAdjList G, int i);    //邻接矩阵深度优先算法
void DFSInter(GraphAdjList G, int i);    //邻接矩阵深度非递归优先算法

void BFSTraverse(GraphAdjList G);    //广度优先遍历

void showGraph(MGraph G);    //显示邻接矩阵
void ShowGraphAdjList(GraphAdjList GL);    //显示邻接表
int main()
{
    MGraph MG;
    GraphAdjList GL;
    CreateMGraph(&MG);
    showGraph(MG);
    CreateALGraph(MG, &GL);
    ShowGraphAdjList(GL);
    DFSTraverse(GL);
    BFSTraverse(GL);
    system("pause");
    return 0;
}

void CreateMGraph(MGraph* G)
{
    int i, j, k, w;
    //     printf("please input number of vertex and edge:\n");
    //     scanf("%d,%d", &G->numVertexes, &G->numEdges);    //输入顶点数和边数
    //     getchar();    //可以获取回车符
    //     for (i = 0; i < G->numVertexes; i++)    //读入顶点信息,建立顶点表
    //         scanf("%c", &G->vers[i]);

    G->numVertexes = 9;
    G->numEdges = 15;
    //读入顶点信息
    G->vers[0] = 'A';
    G->vers[1] = 'B';
    G->vers[2] = 'C';
    G->vers[3] = 'D';
    G->vers[4] = 'E';
    G->vers[5] = 'F';
    G->vers[6] = 'G';
    G->vers[7] = 'H';
    G->vers[8] = 'I';

    //getchar();    //可以获取回车符
    for (i = 0; i < G->numVertexes; i++)
        for (j = 0; j < G->numVertexes; j++)
            G->arc[i][j] = INFINITY;    //邻接矩阵初始化

    G->arc[0][1] = 1;
    G->arc[0][5] = 1;
    G->arc[1][2] = 1;
    G->arc[1][8] = 1;
    G->arc[1][6] = 1;
    G->arc[2][3] = 1;
    G->arc[2][8] = 1;
    G->arc[3][4] = 1;
    G->arc[3][7] = 1;
    G->arc[3][6] = 1;
    G->arc[3][8] = 1;
    G->arc[4][5] = 1;
    G->arc[4][7] = 1;
    G->arc[5][6] = 1;
    G->arc[6][7] = 1;

    for (k = 0; k < G->numVertexes; k++)    //读入numEdges条边,建立邻接矩阵
    {
        for (i = k; i < G->numVertexes; i++)
        {
            G->arc[i][k] = G->arc[k][i];    //因为是无向图,所有是对称矩阵
        }
    }
}


//利用邻接矩阵构建邻接表
void CreateALGraph(MGraph G, GraphAdjList *GL)
{
    EdgeNode* e;
    int i,j;
    //设置顶点数和边表数
    GL->numEdges = G.numEdges;
    GL->numVertexes = G.numVertexes;
    //建立顶点表
    for (i = 0; i < G.numVertexes;i++)
    {
        GL->adjList[i].data = G.vers[i];
        GL->adjList[i].fisrtedge = NULL;
    }
    //建立边表
    for (i = 0; i < G.numVertexes;i++)
    {
        for (j = 0; j < G.numVertexes;j++)
        {
            if (G.arc[i][j]==1)
            {
                e = (EdgeNode*)malloc(sizeof(EdgeNode));
                e->adjvex = j;
                e->next = GL->adjList[i].fisrtedge;
                GL->adjList[i].fisrtedge = e;
            }
        }
    }
}

void DFSTraverse(GraphAdjList G)
{
    int i;
    for (i = 0; i < G.numVertexes; i++)
        visited[i] = false;    //初始化所有顶点状态都是未访问过的未访问状态

    for (i = 0; i < G.numVertexes; i++)
        if (!visited[i])    //对未访问的顶点调用DFS,若是连通图,只会调用一次
            //DFSInter(G, i);
            DFS(G, i);
    printf("\n");
}

void DFS(GraphAdjList G, int i)    //邻接矩阵深度优先算法
{
    int j;
    EdgeNode* p;
    visited[i] = true;    //访问后我们会一直向后退,去访问其他结点,不会再访问这个结点,所有我们不需要再置为false
    printf("%c", G.adjList[i].data);    //打印顶点
    p = G.adjList[i].fisrtedge;
    while (p)
    {
        if (!visited[p->adjvex])
            DFS(G, p->adjvex);
        p = p->next;
    }
}

void DFSInter(GraphAdjList G, int i)    //邻接矩阵深度非递归优先算法
{
    int j, flag;
    Stack s;
    EdgeNode* e;
    InitStack(&s);

    visited[i] = true;    //访问后我们会一直向后退,去访问其他结点,不会再访问这个结点,所有我们不需要再置为false
    printf("%c", G.adjList[i].data);
    Push(&s, i);
    while (!EmptyStack(s))
    {
        i = getTop(s);
        e = G.adjList[i].fisrtedge;
        while (e)
        {
            if (!visited[e->adjvex])
            {
                printf("%c", G.adjList[e->adjvex].data);
                visited[e->adjvex] = true;
                flag = 1;
                Push(&s, e->adjvex);
                break;
            }
            e = e->next;
        }
        if (!flag)
            Pop(&s, &i);
        flag = 0;
    }
}

void BFSTraverse(GraphAdjList G)
{
    LinkQueue Q;
    int i, j, k;
    EdgeNode* q;

    for (i = 0; i < G.numVertexes; i++)
        visited[i] = false;    //初始化所有顶点状态都是未访问过的未访问状态

    InitQueue(&Q);

    for (i = 0; i < G.numVertexes; i++)
    {
        if (!visited[i])    //若是未访问过的就处理
        {
            visited[i] = true;    //设置当前顶点被访问过了
            printf("%c", G.adjList[i].data);    //打印顶点
            EnQueue(&Q, i);    //将此顶点入队
            while (!EmptyQueue(Q))    //若当前顶点不为空
            {
                DeQueue(&Q, &k);    //出队,获取出队行的相关列
                q = G.adjList[k].fisrtedge;
                while (q)
                {
                    if (!visited[q->adjvex])
                    {
                        visited[q->adjvex] = true;    //标记访问过
                        printf("%c", G.adjList[q->adjvex].data);    //输出数据
                        EnQueue(&Q, q->adjvex);    //将其入队
                    }
                    q = q->next;
                }
            }
        }
    }
    printf("\n");
}


void showGraph(MGraph G)
{
    for (int i = 0; i < G.numVertexes; i++)
    {
        for (int j = 0; j < G.numVertexes; j++)
            printf("%2d", G.arc[i][j]);
        printf("\n");
    }
}

void ShowGraphAdjList(GraphAdjList GL)
{
    EdgeNode* e;
    for (int i = 0; i < GL.numVertexes;i++)
    {
        printf("%d: ", i);
        e = GL.adjList[i].fisrtedge;
        while (e)
        {
            printf("%5d", e->adjvex);
            e = e->next;
        }
        printf("\n");
    }
}

 

    原文作者:山上有风景
    原文地址: https://www.cnblogs.com/ssyfj/p/9485501.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞