一种图存储结构【看了之后你会对图的结构有新的认识】

通过一个对象Graph类将图的全部信息封装起来。在该类中要注意几个属性:(首先说明这中存储结构对于大型图比较有效,图的所有信息是存储在数据库中的,所以图的节点数可以从数据库中取得,对于临时图这种结构作用不是很大)

   

public float nodePrestige[];

    public char nodeType[];

    public int nodeIndeg[];

    public int nodeOutdeg[];

    public int adjacentNodeOffset[];

    public StringIntHashMap displayCols; 

    public int adjacentNode[]; // Very Large Array

    public float edgeW[]; // Very Large Array

    public float edgeP[]; // Very Large Array

    public float minEdgeW;

    public float maxNodePrestige;


第一个属性是记录图中所有节点的优先值,在该系统中描述节点都是通过nodeid来进行描述,如nodePrestige[0]=1,这表示nodeid=0节点的优先值为1,以下属性类似。按照表两名大概可以知道各个变量的作用,nodeType描述的是各个节点的类型,nodeIndeg描述的是各个节点的入度,nodeOutdeg描述的是各个节点的出度,adjacentNodeOffset描述的是节点的相邻节点的偏移量,adjacentNode描述的是各个节点的邻接节点结合,大家知道一个节点的邻接节点不止一个,所以大家看到在adjacentNode变量后面有一个注释//Very large array,所以可以知道一个节点的邻接节点在adjacentNode不是一个值,而是一段区间内的值,所以就有了adjacentNodeOffset这个变量,用来记录各个节点的邻接节点是存储在adjacentNode的从哪个位置开始的值,那到哪个地方结束呢?这个问题问的好!我们从上面可以知道每个节点的入度和出度,那么我们图的边是不是由于存在入度和出度才存在的?所以可以知道与一个节点相连边的数目是由入度和出度决定的,不是吗?当然是!所以我们就可以获得一个节点的邻接节点。(从一个节点的偏移量到该偏移量加上入度和出度的值就是与该点相连的邻接节点,例如:我们要获得节点U的邻接节点,于是我们可以获得u的邻接节点的偏移量adjacentNodeOffset[u],u的入度和出度nodeIndeg[u]、nodeOutdeg[u],所以u的所以邻接节点是存储在adjacentNode集合的adjacentNode[adjacentNodeOffset[u]]~ adjacentNode[adjacentNodeOffset[u]+ nodeIndeg[u]+ nodeOutdeg[u]],在adjacentNodeOffset[u]~ adjacentNodeOffset[u]+ nodeIndeg[u]为和u相连的入度节点,adjacentNodeOffset[u]+ nodeIndeg[u]~ adjacentNodeOffset[u]+nodeIndeg[u]+ nodeOutdeg[u]为出度节点),不知大家是否理解了在该系统中存储节点和边的方式。上面获得了邻接节点不是就获得了和u相连的边了吗!可知上面的两个变量是用来存储边的权重和优先值的(edgeW,edgeP)。那么怎么获得一个边呢?也就是如何获得边的权重和优先值呢?下面我将为大家介绍这个。我们有上面可以知道banks下怎么后的一个节点的邻接节点,此处我还用节点u为大家举例。现在的问题是在banks下如何获得和u相连边的权重和优先值。我们知道和u相连的节点是存放在adjacentNode的adjacentNodeOffset[u]~ adjacentNodeOffset[u]+ nodeIndeg[u]+ nodeOutdeg[u]之间。那么我们另i属于adjacentNodeOffset[u]~ adjacentNodeOffset[u]+nodeIndeg[u]+ nodeOutdeg[u]之间,另j=adjacentNode[i],此处j也是代表一个nodeid(nodeid可以在数据库中获得一个node节点的详细信息,要注意的是banks中的数据库表记录节点信息都是都有一个nodeid字段,并且该字段是整型自动递增,所以nodeid是1、2、3、4……,和数组中的编号一致),所以要获得u到j边的权重和优先值,我们就可以edgeW[i],edgeP[i],便是u到j的边的权重和优先级。为什么没是这样呢?不理解的可以往下看,我们可以想想adjacentNode的大小是不是和edgeW,和edgeP的大小一样?我们上面讲过:由于节点存在入度和出度才有边,如果一个节点既没有入度也没有出度那么它就是孤立的点了。所以adjacentNode和edge、edgeP的位置是对应的。所以才有:edgeW[i],edgeP[i],便是u到j的边的权重和优先级。不知大家是否想通!

图中还有两个属性用的非常恰当:

    private HashMap nodeCache;

    private LinkedListnodeLRUList;


第一个变量一看就会知道是一个缓存的变量,第二个变量则是通过一个链表来存储最近最少使用的节点集合。在banks系统中为了节省内存,所有节点信息都是通过nodeid(是数字类型)来描述,甚至可以连节点的类型意识用简单的数字来存储,因为这样能够节省没必要的内存。那么说了这么多nodeCache和nodeURLList是干嘛呢的?由于我们要获得不是一个nodeid,而是一个节点的详细信息,我们不可能把所有的节点信息都存储在内存中,有两个限制:(1)内存不够,(2)需要大量的访问数据库。Banks为了避免这两个限制,首先是将以前的信息用数字类描述,再就是通过上面的两个变量。大家会问那么nodeCache是用来存什么信息的啊?大家都可以看到它是一个Map类型,Map大家都知道是由键值对组成的,那么nodeCache的键是什么,值是什么呢?键是nodeid,值是该节点在数据库中的存储位置,此处的存储位置是什么?也就是该节点是在哪个表的哪个字段。不知大家是否明白(因为在banks中它是将节点分类存储在各个表中的,如:Author、writer、cite、paper。在将这些表的信息合并为一个表中,这个表中就有一个nodeid,tableid,rowid字段,所以此处的nodeid不是一个真正的nodeid而是一个过渡的nodeid,这样做是为了使的系统中的所有节点的nodeid都遵循统一的编号)。由于nodeCache的大小在系统中是设置好的,所以它不能无限的装载信息。所以就有了nodeURLList变量,来控制当nodeCache满时,哪些节点要移除。可知在nodeURLList中的第一个是最少使用的(由于在系统中都是将新的信息插入到nodeURLList最后),这里并不是完全实现像操作系统中的最近最少使用的算法,但是能够达到一定的效果。这里让我想到了为何该系统在获取节点的存储位置时用到了缓存队列,为何不对节点的详细信息也做同样的处理,这样不就又可以避免访问数据库吗?此处待大家探讨!

这篇文章只是帮助大家理解如何存储图结构的,但也未必完全中却,只供参考!


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值