算法(1):DFS&BFS

本小结使用C完成了图的深度优先搜索和广度优先搜索的Demo
输入样例都是无向图,并且节点使用整数表示
DFS和BFS时使用的都是上述邻接矩阵存储的图

(一)图

可以使用邻接矩阵或者邻接表存储图

(0)定义

  • 对于无向图
    • w为0:表示顶点重合
    • w为∞:表示顶点之间没有边
    • w为1:表示顶点之间有一条边
  • 对于有向图
    • w为n:表示顶点之间距离/权值为n(为0时表示两点重合)
    • w为-1:表示顶点之间没有边

(1)邻接矩阵存储

  • 使用二维数组存储矩阵
    • 矩阵中的第i行第j列表示图的顶点i到顶点j之间的距离:对于无向图来说,1表示有连接,∞表示没有连接,0表示i和j是相同的点(距离为0)
    • 二维数组是沿对角线对称的:因为顶点i到顶点j的距离==顶点j到顶点i的距离
    • 使用C实现
  • main.c:
#include <stdio.h>
#include <stdlib.h>
#include "method.c"

int main() {
    AdjMatrix G;
    CreateGraph(&G);
    PrintGraph(&G);
	//DFSTraverse(&G);
    //BFSTraverse(&G);
    system("pause");
    return 0;
}
  • method.c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "include.h"
#include "include.h"
#define true 1
#define false 0

//创建无向图
void CreateGraph(AdjMatrix *G){
    int n,e;
    int vi,vj,w,i,j;
    printf("请输入图的顶点数和边数:");
    scanf("%d%d",&n,&e);
    G->numV = n;
    G->numE = e;
    //初始化图
    for(i=0;i < n; i++){
        for(j=0; j < n; j++){
            if(i == j)
                G->Edge[i][j] = 0;
            else
                G->Edge[i][j] = INT_MAX;
        }
    }
    //存放顶点
    for(i=0;i < n; i++){
        printf("请输入%d个顶点的信息",i+1);
        scanf("%d",&G->Vertices[i]);
    }
    printf("\n");

    for(int i=0; i < e; i++){
        printf("请输入边的信息i,j,w(用空分隔)");
        scanf("%d%d%d",&vi,&vj,&w);

        G->Edge[vi-1][vj-1] = w;
        G->Edge[vj-1][vi-1] = w;
    }
}

//打印无向图
void PrintGraph(AdjMatrix *G){
    int i,j;
    printf("\n输出顶点的信息:\n");
    for(i=0; i < G->numV; i++){
        printf("%8d",G->Vertices[i]);
    }

    printf("\n输出邻接矩阵\n");
    printf("\t");
    for(i=0; i < G->numV; i++){
        printf("%8d",G->Vertices[i]);
    }

    for(i=0; i < G->numV; i++){
        printf("\n%8d",i+1);
        for(j=0; j < G->numV; j++){
            if(G->Edge[i][j] == INT_MAX)
                printf("%8s","∞");
            else
                printf("%8d",G->Edge[i][j]);
        }
        printf("\n");
    }
}
  • include.h
#include <stdio.h>
#include <stdlib.h>
#define MaxVertices 100 //最大顶点数
typedef struct{ //定义邻接矩阵结构体
    int Vertices[MaxVertices]; //顶点数组
    int Edge[MaxVertices][MaxVertices]; //边的数组
    int numV; //vertices
    int numE; //edges
}AdjMatrix;
  • 测试数据
5 7
1 2 3 4 5
1 3 1
1 5 1
2 3 1
2 4 1
2 5 1
3 5 1
4 5 1

(一)深度优先搜索

深度优先搜索和广度优先搜索使用的都是回溯的思想

  • 深度优先搜索Deepth First Search
  • 构造一个标记数组visited,判定节点是否被访问过
  • 首先从图的初始节点开始,如果节点没有被访问过,对该节点进行单点DFS
    • 对于单点,首先标记数组visited,然后对于该点的相邻点,如果没有被访问过,则递归进行DFS
    • 对于一个点,如果该点的所有相邻节点都被访问过,那么会回溯到递归的上一层
//单点DFS
void DFS(AdjMatrix *G, int k, int* vi){
    vi[k] = true;
    printf("目前正在访问的节点是:%d\n",G->Vertices[k]);
    for(int i=0; i < G->numV; i++){
        if(G->Edge[k][i] == 1 && !vi[i])
            DFS(G,i,vi);
    }
}


//深度优先搜索图
void DFSTraverse(AdjMatrix *G){
    int visited[G->numV];
    for(int i=0; i < G->numV; i++){
        visited[i] = false;
    }
    printf("\n");
    for(int i=0; i < G->numV; i++){
        if(!visited[i]){
            DFS(G,i,visited);
        }
    }
}

(二)广度优先搜素

  • 广度优先搜索Breadth First Search
    • 也需要一个visited标记数组
    • 使用队列存储当前访问的顶点:对于一个顶点A,首先让A入队同时访问A节点;
    • 如果队列不为空,那么取出队首元素B,找到所有和B相邻并且没有被访问过的节点,以此访问并入队
void BFSTraverse(AdjMatrix *G){
    int visited[G->numV];
    for(int i=0; i < G->numV; i++){ //初始化标记数组
        visited[i] = false;
    }
    int queue[G->numV]; //使用数组表示简单队列
    int rear = -1; //队列尾
    int front = -1; //队列首

    //核心算法
    for(int i=0; i < G->numV; i++){

        if(!visited[i]){
            visited[i] = true;
            printf("正在访问的节点是%d:\n",G->Vertices[i]);
            queue[++rear] = i;
        }

        while(front != rear){
            int k = queue[front];
            front++;

            for(int j=0; j < G->numV; j++){
                if(G->Edge[k][j] == 1 && !visited[j]){
                    visited[j] = true;
                    printf("正在访问的节点是%d:\n",G->Vertices[j]);
                    queue[++rear] = j;
                }
            }
        }

    }
}
  • 测试样例
7 7
1 2 3 4 5 6 7
1 2 1
2 3 1
3 4 1
1 5 1
1 6 1
5 6 1
5 7 1

输出:

正在访问的节点是1:
正在访问的节点是3:
正在访问的节点是4:
正在访问的节点是6:
正在访问的节点是2:
正在访问的节点是7:
正在访问的节点是5:

测试图数据参考:http://www.cnblogs.com/skywang12345/p/3711483.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值