简单好理解的图论讲解(图论的三种表现形式以及相关操作)

        图论是数据结构与算法中必须逾越的一座大山,适用范围非常广泛,当然也具有一定的难度,本人也是今年第一次学习图论的知识点,不能说掌握的很好,但我会尽可能的把我学会的知识点分享给大家,在写这篇博客之前我也查阅了很多大牛的图论分享,也算基本上涵盖了图论的重要知识点,如有错误还望各路大神斧正。另外以下程序都是由C语言编写的,海域。

        首先我们简单认识一下图论,我举一个最简单的例子,就是我们常用的百度或者高德地图,我们在导航时,背后的本质就是图论的各种算法,例如是否有通路可以抵达,或者最短路径是哪条线路等,所以图论的应用是非常广泛的,包括全市公交线路,如何帮我我们快速找到最快抵达的路线,这都是图论的功劳。另外值得注意的是,在计算图论的复杂度的时候,我们不再用n进行计算了,而是要以图的顶点个数V和边的个数E进行计算。那么接下来我们就开始正式讲解。

        图论主要有三种表现形式,分别是边的数组(Array of edges),临接矩阵(Adjacency matrix)和临接链表(Adjacency list)。其中临接矩阵是最好理解,也是大家一定要掌握的,而我个人比较喜欢临接链表,三种形式主要是数据储存的方式不同,但背后的理论是相似的,学会一个另外的都会变得很好理解。当然这三种我都会给大家一一介绍的,各位看官可以根据自己的需求选择相应的方法。

1. Array-of-edges

        边的数组主要是以数组的形式去储存顶点和边的信息,具体说应该是二维数组。具体的程序细节都在注释里面,大家可以结合代码去理解。

typedef int Vertex;

typedef struct Edge* edge;
struct Edge {
    Vertex v; // 每条边的起点编号
    Vertex w; // 每条边的终点编号
};

typedef struct graph* Graph;
struct graph {
    edge **edges; //指向结构体指针的指针
    int numberOfV; //顶点的个数
    int numberOfE; //边的个数
};


graph* newGraph(int numberOfV) { //创建一个新的图
    graph* newGraph = malloc(sizeof (struct graph));
    newGraph->edges = malloc(sizeof (edge*) * 100); //构建二维数组(这是二维数组的第一层,定义大小)
    //初始化顶点和边的数量,边的数量要根据插入函数来决定
    newGraph->numberOfE = 0;
    newGraph->numberOfV = numberOfV;
    return newGraph;
}

//添加一条边
void append_edge(graph *g, int v, int w){ // 输入每条边起点和终点的编号
    edge *newEdge = malloc(sizeof (struct Edge));
    newEdge->v = v;
    newEdge->w = w;
    g->edges[g->numberOfE] = newEdge; //由创建街道可知,Graph->edges是一个可以存储100个边的数组,这一步的意思是从第0个开始存储边,起点和终点都同时存入了
    g->numberOfE++;
}

void showGraph (graph* g){
    printf("number of vertex: %d\n", g->numberOfV);
    printf("number of edges: %d\n", g->numberOfE);
    for (int i = 0; i < g->numberOfE; i++) {
        printf("edge[%d] v:%d - w:%d\n", i+1, g->edges[i]->v, g->edges[i]->w);
    }
}

void freeGraph(graph* g){
    for (int i = 0; i < g->numberOfE; i++)
        free(g->edges[i]);
    free(g->edges);
    free(g);
}

int main(void){
    graph *g = newGraph(6);

    append_edge(g, 1, 2);
    append_edge(g, 1, 3);
    append_edge(g, 1, 4);

    showGraph(g);
    freeGraph(g);
}

2. Adjacency matrix

        矩阵相信大家都不陌生了,矩阵可以非常简单的让我们画出一个图,具体操作其实很简单,就是两个点若没有边则填0,若有边则填1.本质上也是二维数组,但是边的数组是有边才输入顶点编号,而矩阵是所有顶点都要写出来,然后两两不断的做对比。

//插入/删除一条边的算法法度是O(1),直接找到改为1/0即可,查找是O(E)
//创建(初始化,存储)一个矩阵的算法法度是O(v^2),
typedef int Vertex;

typedef struct edge { //类似于一个房屋
    Vertex v; // 每条边的起点编号
    Vertex w; // 每条边的终点编号
}Edge;

typedef struct graph{ //类似于一个街道
    int **matrix; //定义为二维数组
    int number_of_v; //顶点的数量
    int number_of_e; //边的数量
}Graph;


Graph *new_graph(int number_of_v){ //创建一个矩阵并将其初始化
    Graph *new_graph = malloc(sizeof(struct graph));
    new_graph->matrix = malloc(sizeof (int *) * number_of_v);
    for (int i = 0; i < number_of_v; i++) { //二维数组的初始化和赋值必须用两个for循环
        new_graph->matrix[i] = malloc(sizeof (int) * number_of_v); //这两个malloc就是建立矩阵的过程。00,01,02
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值