一種圖存儲結構【看了之後你會對圖的結構有新的認識】

通過一個對象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最後),這裏並不是完全實現像操作系統中的最近最少使用的算法,但是能夠達到一定的效果。這裏讓我想到了爲何該系統在獲取節點的存儲位置時用到了緩存隊列,爲何不對節點的詳細信息也做同樣的處理,這樣不就又可以避免訪問數據庫嗎?此處待大家探討!

這篇文章只是幫助大家理解如何存儲圖結構的,但也未必完全中卻,只供參考!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章