【数据结构】

图的概念

图:有多个前驱节点和多个后继节点
图(Graph*)是一种非线性数据结构,形式化描述为:其中,V={Vi | Vi ∈datatype, i=0,1,……,n-1} 是图中元素Vi(称为顶点Vertex )的集合,n=0时,V为空集,记为φ。
R是顶点之间的关系集,P(Vi,Vj)为顶点Vi与Vj之间是否存在路径的判定条件,即若Vi与Vj之间的路径存在,则关系< Vi,Vj >∈R。

无向图

设Vi、Vj为图中的两个顶点,若关系<Vi,Vj>无方向性,
即:
当<Vi,Vj>∈R时,必有<Vj,Vi>∈R,则称此时的图为无向图。
关系用(Vi,Vj)或(Vj,Vi)表示,
称为图中的一条边(Edge)(Vi,Vj)
image-20220829144824979

有向图

1)有向图(Digraph)
设 Vi、Vj为图中的两个顶点,若关系**<** Vi,Vj**>**存在方向性,即:< Vi,Vj>≠<Vj,Vi >,则称相应的图为有向图。<Vi,Vj>∈*R,表示从顶点 Vi到Vj的一条弧(Arc):
< Vi,Vj > Vi为弧尾,Vj为弧头。
image-20220829144531271

网(Network)若在图的关系<Vi,Vj>或(Vi,Vj)上附加一个值w
image-20220829145155037

子图

设图G=(V,R)、G’=(V’,R’),若且,则称G’为G的子图。例5-1、例5-2中G1和G2的如下:
image-20220829145459492 image-20220829145517300

顶点的度

在这里插入图片描述

图的存储

由于图中顶点间的关系(弧或边)无规律,故对图的存储较之表和树要复杂些,需要根据图的具体应用来构造图的存储结构。常用的存储表示有“数组表示法”、“邻接表”、“十字链表”和“邻接多重表”。

图的数组表示法(邻接矩阵)

image-20220829150958221

图的邻接表表示法
V0 -V2-V3-

V1 -V2-

V2 -V0-V1-V5-

V3 -V0-V4-V5-

V4 -V3-

V5 -V2-V3-

图的实例

图的创建
graph_t * GraphCreate(void)
{
    graph_t *g;

    //1.分配图的内存
    if((g = (graph_t *)malloc(sizeof(*g)))==NULL){
        printf("malloc memory graph error\n");
        return NULL;
    }
    //2.对图中的数据赋值
    for(int i=0;i<N;i++){
        g->data[i] = i;
    }

    //3将顶点和顶点的关系初始化为0
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            g->relation[i][j] = 0;
        }
    }
    
    return g;
}
输入顶点的关系
void GraphInputRelation(graph_t* g)
{
    int i, j;
    while (scanf("(%d,%d)", &i, &j) == 2) {
        g->relation[i][j] = g->relation[j][i] = 1;
    }
}
输出图
void GraphShow(graph_t* g)
{
    printf("   ");
    for (int i = 0; i < N; i++) {
        printf("V%d ", g->data[i]);
    }
    putchar(10);

    for (int i = 0; i < N; i++) {
        printf("V%d ", g->data[i]);
        for (int j = 0; j < N; j++) {
            printf("%d  ",g->relation[i][j]);
        }
        putchar(10);
    }
}
图的整体代码

graph.h

#ifndef __GRAPH_H__
#define __GRAPH_H__

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

#define N 6
#define datatype int

typedef struct{
    datatype data[N];
    int relation[N][N];
}graph_t;

graph_t * GraphCreate(void);
void GraphInputRelation(graph_t *g);
void GraphShow(graph_t *g);
#endif

graph.c

#include "graph.h"
graph_t* GraphCreate(void)
{
    graph_t* g;

    // 1.分配图的内存
    if ((g = (graph_t*)malloc(sizeof(*g))) == NULL) {
        printf("malloc memory graph error\n");
        return NULL;
    }
    // 2.对图中的数据赋值
    for (int i = 0; i < N; i++) {
        g->data[i] = i;
    }

    // 3将顶点和顶点的关系初始化为0
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            g->relation[i][j] = 0;
        }
    }

    return g;
}

void GraphInputRelation(graph_t* g)
{
    int i, j;
    while (scanf("(%d,%d)", &i, &j) == 2) {
        g->relation[i][j] = g->relation[j][i] = 1;
    }
}

void GraphShow(graph_t* g)
{
    printf("   ");
    for (int i = 0; i < N; i++) {
        printf("V%d ", g->data[i]);
    }
    putchar(10);

    for (int i = 0; i < N; i++) {
        printf("V%d ", g->data[i]);
        for (int j = 0; j < N; j++) {
            printf("%d  ",g->relation[i][j]);
        }
        putchar(10);
    }
}

main.c

#include "graph.h"

int main(int argc,const char * argv[])
{
    graph_t *g;
    //1.创建图
    g = GraphCreate();
    if(g == NULL){
        printf("graph create error\n");
        return -1;
    }
    //2.输入关系
    GraphInputRelation(g);
    //3.输出图
    GraphShow(g);

    return 0;
}

执行的效果
在这里插入图片描述

图的搜索

深度优先

深度优先搜索(Depth First Search,简称DFS)
1.算法思路
类似树的先序遍历。设初始时,图中各顶点均未被访问,从图中某顶点(设为V0)出发,访问V0,然后搜索V0的一个邻接点Vi,若Vi未被访问,则访问之,再搜索Vi的一个邻接点(深度优先)……。若某顶点的邻接点全部访问完毕,则回溯(Backtracking)到它的上一顶点,然后再从此顶点又按深度优先的方法搜索下去,……,直到能访问的顶点都访问完毕为止。

eg:

image-20220829155741274
深度优先的顺序:V0,V2,V1,V5,V3,V4

int dfs_r[N] = {0};
void GraphDFS(graph_t *g,int i)
{
    //1.先将i节点的数据打印出来,并将vi节点标记为被访问过
    printf("V%d\n",g->data[i]);
    dfs_r[i] = 1;

    //2.查找关系
    for(int j=0;j<N;j++){
        if(g->relation[i][j]==1 && dfs_r[j]==0){
            GraphDFS(g,j);
        }
    }
}

在这里插入图片描述
深度优先搜索的顺序:A,B,D,C,E,F

int dfs_r[N] = {0};
void GraphDFS(graph_t *g,int i)
{
    //1.先将i节点的数据打印出来,并将vi节点标记为被访问过
    printf("%c\n",g->data[i]);
    dfs_r[i] = 1;

    //2.查找关系
    for(int j=0;j<N;j++){
        if(g->relation[i][j]==1 && dfs_r[j]==0){
            GraphDFS(g,j);
        }
    }
}
广度优先

广度优先搜索(Breadth First Search),简称BFS。
1.算法思路
​ 类似树的按层次遍历。初始时,图中各顶点均未被访问,从图中某顶点(设V0)出发,访问V0,并依次访问V0的各邻接点(广度优先)。然后,分别从这些被访问过的顶点出发,仍按照广度优先的策略搜索其它顶点,……,直到能访问的顶点都访问完毕为止。控制广度优先的正确搜索,要用到队列技术,即访问完一个顶点后,让该顶点的序号进队。然后取相应队头(出队),考察访问过的顶点的各邻接点,将未访问过的邻接点访问后再依次进队,……,直到队空为止。

eg:

image-20220829162419754
广度优先:A,B,D,F,E,C

int bfs_r[N] = {0};
void GraphBFS(graph_t *g,int i)
{
    linkqueue_t *q;
    int pos;
    //1.创建一个队列
    q = LinkQueueCreate();

    //2.让第0个节点入队
    LinkQueueEnQueue(q,i);
    bfs_r[i]=1;
    //3.循环搜索,队列为空的时候
    while(!LinkQueueIsEmpty(q)){
        //4.出队
        pos = LinkQueueDeQueue(q);
        printf("%c\n",g->data[pos]);
        
        //5.找关系
        for(int j=0;j<N;j++){
            if(g->relation[pos][j]==1 &&bfs_r[j]==0){
                 LinkQueueEnQueue(q,j);
                 bfs_r[j]=1;
            }
        }

    }
}
图的整体的代码

graph.h

#ifndef __GRAPH_H__
#define __GRAPH_H__

#include <stdio.h>
#include <stdlib.h>
#include "linkqueue.h"
#define N 6
#define datatype int

typedef struct{
    datatype data[N];
    int relation[N][N];
}graph_t;

graph_t * GraphCreate(void);
void GraphInputRelation(graph_t *g);
void GraphShow(graph_t *g);
void GraphDFS(graph_t *g,int i);
void GraphBFS(graph_t *g,int i);
#endif

graph.c

#include "graph.h"
graph_t* GraphCreate(void)
{
    graph_t* g;

    // 1.分配图的内存
    if ((g = (graph_t*)malloc(sizeof(*g))) == NULL) {
        printf("malloc memory graph error\n");
        return NULL;
    }
    // 2.对图中的数据赋值
    for (int i = 0; i < N; i++) {
        g->data[i] = 'A'+i;
    }

    // 3将顶点和顶点的关系初始化为0
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            g->relation[i][j] = 0;
        }
    }

    return g;
}

void GraphInputRelation(graph_t* g)
{
    int i, j;
    while (scanf("(%d,%d)", &i, &j) == 2) {
        g->relation[i][j] = g->relation[j][i] = 1;
    }
}

void GraphShow(graph_t* g)
{
    printf("  ");
    for (int i = 0; i < N; i++) {
        printf("%c ", g->data[i]);
    }
    putchar(10);

    for (int i = 0; i < N; i++) {
        printf("%c ", g->data[i]);
        for (int j = 0; j < N; j++) {
            printf("%d  ",g->relation[i][j]);
        }
        putchar(10);
    }
}
//通过dfs_r标记当前节点是否被访问过 
//0没有被访问过,如果1表示被访问过
int dfs_r[N] = {0};
void GraphDFS(graph_t *g,int i)
{
    //1.先将i节点的数据打印出来,并将vi节点标记为被访问过
    printf("%c\n",g->data[i]);
    dfs_r[i] = 1;

    //2.查找关系
    for(int j=0;j<N;j++){
        if(g->relation[i][j]==1 && dfs_r[j]==0){
            GraphDFS(g,j);
        }
    }
}

int bfs_r[N] = {0};
void GraphBFS(graph_t *g,int i)
{
    linkqueue_t *q;
    int pos;
    //1.创建一个队列
    q = LinkQueueCreate();

    //2.让第0个节点入队
    LinkQueueEnQueue(q,i);
    bfs_r[i]=1;
    //3.循环搜索,队列为空的时候
    while(!LinkQueueIsEmpty(q)){
        //4.出队
        pos = LinkQueueDeQueue(q);
        printf("%c\n",g->data[pos]);
        
        //5.找关系
        for(int j=0;j<N;j++){
            if(g->relation[pos][j]==1 &&bfs_r[j]==0){
                 LinkQueueEnQueue(q,j);
                 bfs_r[j]=1;
            }
        }

    }
}

main.c

#include "graph.h"

int main(int argc,const char * argv[])
{
    graph_t *g;
    //1.创建图
    g = GraphCreate();
    if(g == NULL){
        printf("graph create error\n");
        return -1;
    }
    //2.输入关系
    GraphInputRelation(g);
    //3.输出图
    GraphShow(g);

    //4.深度优先
    GraphDFS(g,0);
    puts("---------------------------");
    //5.广度优先
    GraphBFS(g,0);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值