我们在使用像QQ ,微信,微博,快手,抖音等社交软件的过程中经常需要添加好友,关注好友和被好友关注。这个过程中 这样的社交网络中的好友关系就需要被存储下来,存储在各个公司的后台服务器之上,都会作为每个公司的数据资产来进行自己核心业务的开发(视频推荐、好友推荐。。。)

这个用来保存好友关系的数据结构就是 图,接下来探索一下这个非线性数据结构的基本实现。

图的一些基本概念如上导图,已经描述的很清楚了,这里重点说的是图的图存储方式。
基本的存储方式有两种:

  • 邻接矩阵
  • 邻接表

邻接矩阵的底层依赖一个二维数组。对于无向图来说,如果顶点i与顶点j之间有边,我们就将A[i][j]A[j][i]
标记为1;对于有向图来说,如果顶点i到顶点j之间,有 一条箭头从顶点i指向顶点j的边,那我们就将A[i][j]标记为1。同理,如果有一条箭头从顶点j指向顶点i的边,我们就将A[j][i]标记为1。对于带权图,数组中就存储 相应的权重。

用数组表示的底层数据结构能够提供高效的查找能力,但是缺点也很明显,就是浪费空间过于严重,针对无向图的存储中只需要保存一个A[i][j]即可。

邻接表底层依赖链表进行数据存储,能够解决邻接矩阵浪费空间严重的问题,链表只有添加了新节点才会分配空间。整体的实现有点像散列表。
对于无向图来说,每一个顶点表示一个链表,与该顶点相连的其他顶点依次添加到该顶点的链表之上,类似如下:

有向图也是类似的,链表上仅保存该顶点指向的顶点

链表本身的查找效率比较低,需要顺链访问,在邻接表中可以将底层的链表存储结构用更加高效的动态查找数据结构来代替(链表和红黑树)。

以上数据结构都是存放在内存中的,但是实际的线上环境社交关系数据量以TB级别进行存储,这个时候数据量远超内存,便需要有持久化能力,需要对图的内存数据结构进行编码。
以邻接表距离,遍历邻接表,将顶点和对应链接顶点别编码为(user_id, follower_id),后续的关系依次追加。像常见的分布式图存储,大体也是类似的方式进行存储,只不过底层磁盘的编码格式更为复杂一点。可以类似与sst中的data_block,index block,footer 依次索引到datablock中,datablock保存实际的user_id和follower_id信息。

同时图存储 系统也希望将依赖于图的众多查找算法(bfs,dfs,djs,djkstra,A*,启发式搜索等)下沉到存储层,从而节省计算层的CPU开销。这时候,一个高效的分布式图存储系统的雏形边有了(只是单机的,分布式能力还是一大部分工作量),当然为用户提供可以访问的图语言也是完善系统的一部分。

接下来简单实现一下邻接表和邻接矩阵的图存储功能:

  • 邻接表
    graph_list.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>typedef struct Graph_vertex vertex;typedef struct Graph_edge { // 边struct Graph_vertex *v; // 该边链接的顶点struct Graph_edge *next; // 用链表管理的链接同一顶点的下一条边
    }edge;typedef struct Graph_vertex { // 顶点int data;   // 顶点的值edge *e; // 顶点的边 链表管理的相连接的边
    }vertex;#define MAX_GRAPH (1 << 8)
    typedef struct Graph{vertex *vxs[MAX_GRAPH];
    }graph;void init_graph(graph *g){int i = 0;for (;i < MAX_GRAPH; i++) {g->vxs[i] = NULL;}
    }/* 创建顶点 */
    vertex *create_vertex(int data) {if(data < 0) {return NULL;}vertex * v = NULL;v = (vertex *)malloc(sizeof(vertex));if(v == NULL) {return NULL;}v->data = data+1;v->e = NULL;return v;
    }/* 创建边 */
    edge *create_edge(vertex *v){if(v == NULL) {return NULL;}edge *e;e = (edge *)malloc(sizeof(edge));if(e == NULL) {return NULL;}e->v = v;e->next = NULL;return e;
    }/* 为顶点v1 插入边 */
    void insert_edge(vertex *v1, vertex *v2) {if (v1 == NULL || v2 == NULL) {return;}edge **e;e = &v1->e;while(*e) {e = &(*e)->next;}*e = create_edge(v2);
    }/* 打印邻接表 */
    void dump_graph(graph *g) {int i;for(i = 0;i < MAX_GRAPH; ++i) {vertex *v = g->vxs[i];edge *e;if(v == NULL) {continue; }printf("Vertex[%d]:%2d->",i+1, v->data);e = v->e;while(e) {if(e->next != NULL) {printf("%2d->", e->v->data);}else {printf("%2d", e->v->data);}e = e->next; }printf("\n");}
    }/* 1 ----- 2 ----- 3|     / |     /|    /  |    / |   /   |   /  |  /    |  /   | /     | /    4 ----- 5
    */
    void create_graph(graph *g) {int i = 0;init_graph(g);for (;i < 5; ++i) {g->vxs[i] = create_vertex(i);}// 链接1--2, 1--4insert_edge(g->vxs[0],g->vxs[1]);insert_edge(g->vxs[0],g->vxs[3]);// 链接2--1,2--3,2--4,2--5insert_edge(g->vxs[1],g->vxs[0]);insert_edge(g->vxs[1],g->vxs[2]);insert_edge(g->vxs[1],g->vxs[3]);insert_edge(g->vxs[1],g->vxs[4]);// 链接3--2,3--5insert_edge(g->vxs[2],g->vxs[2]);insert_edge(g->vxs[2],g->vxs[4]);// 链接4--1,4--2,4--5insert_edge(g->vxs[3],g->vxs[0]);insert_edge(g->vxs[3],g->vxs[1]);insert_edge(g->vxs[3],g->vxs[5]);// 链接5--2,5--3,5--4insert_edge(g->vxs[4],g->vxs[1]);insert_edge(g->vxs[4],g->vxs[2]);insert_edge(g->vxs[4],g->vxs[3]);
    }int main() {graph g;create_graph(&g);dump_graph(&g);return 0;
    }
    
  • 邻接矩阵
    graph_matrix.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>#define MAX_GRAPH (1 << 8)int *graph[MAX_GRAPH];void init_graph(int size) {if (size > MAX_GRAPH) {return ;}int i = 0;int j = 0;for (; i < size; ++i) {graph[i] = (int*)malloc(size*sizeof(int));for (;j < size; ++j){graph[i][j] = 0;}}
    }void add_edge(int v1, int v2) {graph[v1][v2] = 1;graph[v2][v1] = 1;
    }void print_graph(int size) {int i = 0;int j = 0;for (; i < size; ++i) {for (; j < size; ++j)  {printf("%d ", graph[i][j]);}printf("\n");}
    }/* 1 ----- 2 ----- 3|     / |     /|    /  |    / |   /   |   /  |  /    |  /   | /     | /    4 ----- 5
    */
    void create_graph(int size) {init_graph(size);add_edge(0,1);add_edge(0,3);add_edge(1,0);add_edge(1,2);add_edge(1,3);add_edge(1,4);add_edge(2,1);add_edge(2,4);add_edge(3,0);add_edge(3,1);add_edge(3,4);add_edge(4,1);add_edge(4,2);add_edge(4,3);
    }int main() {create_graph(6);print_graph(6);return 0;
    }
    

数据结构 -- 图与图存储相关推荐

  1. 【数据结构——图和图的存储结构】

    目录 一.图的定义和基本术语(Graph) (一)图的定义 (二)图的基本术语 一.图的存储结构 (一)邻接矩阵(Adjacency Matrix) 1.无向图的邻接矩阵 2.有向图的邻接矩阵 3.网 ...

  2. 数据结构-图(图的定义、分类、基本术语和存储结构)

    图 图(Graph)是由莱昂哈德·欧拉1在1736年首先引进的一类很重要的非线性结构,可称为图形结构或网状结构.图的应用领域非常广泛,例如:电路分析.工程规划.化合物分类.统计力学.自动化.语言学等. ...

  3. 7张图揭晓RocketMQ存储设计的精髓

    简介:RocketMQ 作为一款基于磁盘存储的中间件,具有无限积压能力,并提供高吞吐.低延迟的服务能力,其最核心的部分必然是它优雅的存储设计. RocketMQ 作为一款基于磁盘存储的中间件,具有无限 ...

  4. 数据结构基础:图结构的学习笔记

    1.图的定义 图是比树更加复杂的数据结构,在图的结构当中,任意两个节点之间都有可能有直接关系,所以图中一个节点的前驱和后继的数目是没有限制的. 2.图的用途 用于描述各种复杂的数据对象,在自然科学.社 ...

  5. noj数据结构稀疏矩阵的加法十字链表_数据结构之:图

    导读 1. 什么是图?图的存储方式? 2. 图的遍历(深度优先搜索,广度优先搜索) 3. 最短路径 1. 什么是图?图的存储方式? 前面总结了"树"这种数据结构,而这篇博客总结的是 ...

  6. 数据结构探险之图篇(上)理论篇

    数据结构探险之图篇 什么是图? 如下图:无向图 & 有向图 箭头分方向. 无向图中每条认为有来有回两条线 无向图&有向图 图中的概念: 有向图中的概念 结点称为顶点. 之间的线称为弧. ...

  7. 数据结构实践项目——图的基本运算及遍历操作

    本文是针对[数据结构基础系列(7):图]中第1-9课时的实践项目. 0701 图结构导学 0702 图的定义 0703 图的基本术语 0704 图的邻接矩阵存储结构及算法 0705 图的邻接表存储结构 ...

  8. 数据结构实验6图的应用-行车路线问题

    需求分析 0.问题描述 小明和小芳出去乡村玩,小明负责开车,小芳来导航. 小芳将可能的道路分为大道和小道.大道比较好走,每走1公里小明会增加1的疲劳度.小道不好走,如果连续走小道,小明的疲劳值会快速增 ...

  9. 图(Graph)-图的存储

    1.图的存储类型 顺序存储-邻接矩阵 链式存储-邻接表 9:19 2.用邻接矩阵存储的方式表示无向图的结构 2.1 邻接矩阵 图的邻接矩阵存储方式是用两个数组来表示图. 一个数组存储图中的顶点信息: ...

最新文章

  1. ubuntu16.04安装英伟达(NVIDIA)驱动——run文件安装
  2. php和java的语法区别_PHP 和 Java 的主要区别有哪些?
  3. Mysql主主复制高可用解决方案
  4. HTML 5 input type 属性
  5. 【C language】C语言感悟之const
  6. 20161104面试题-面试常问问题
  7. Pycharm新建Django项目:Hello World示例
  8. expect返回值给shell_使用expect实现shell自动交互
  9. STM32 连续操作flash
  10. 法拉第未来宣布汉福德工厂获得最终生产使用资质
  11. Pythonic:递归、回溯等5种方法生成不重复数字整数
  12. 第二章 ASP.NET MVC (控制器向视图传递值(一))
  13. python如何测试rabbit_Python如何检测到我的RabbitMQ密码失败?
  14. 有这就够了小香港五味俱全——专升本高数
  15. 微商选择满意商品的方法
  16. libreelec投屏_低配置主机安装Kodi操作系统 - LibreELEC
  17. 计算机散热 测试,散热拷机实测_笔记本评测-中关村在线
  18. 数据可视化中的格式塔心理学
  19. i2c-tool使用详细说明
  20. pap认证过程_思科课件8、PAP认证、CHAP认证

热门文章

  1. android 之 Intent、broadcast
  2. 如何给iOS应用添加原生的二维码扫描功能
  3. java与.net比较学习系列(7) 属性
  4. 得到最后的自增长列的最后一个值
  5. WPF初探--RichTextBox
  6. Tile Racer — 3D 赛车游戏
  7. BaseTDI.sys 瑞星卡巴冲突,导致机器蓝屏
  8. usaco A game
  9. flume写入mysql_Flume高级之自定义MySQLSource
  10. mysql数据库比对视频教程_MySQL数据库全学习实战视频教程(27讲 )