1. 程式人生 > >圖資料儲存結構詳解

圖資料儲存結構詳解

邊關係表
邊編號 起始節點編號 終止節點編號 權重
1 1 3 5
2 1 5 4
3 1 6 2
4 2 3 1
5 2 5 6
6 3 1 5
7 3 2 1
8 3 4 3
9 4 3 3
10 4 6 5
11 5 1 4
12 5 2 6
13 6 1 2
14 6 4 5
         由於上面給出的圖是無向圖,所以兩個節點之間的邊的關係是相互的,如V1——>V3那麼V3——>V1。所以邊的關係表中有14條記錄。上面列舉出了節點的儲存結構和邊的儲存結構,那麼如何根據這些資訊還原圖的結構呢?其實要還原圖,只需關注邊的關係表就夠了,而節點關係表只是儲存節點詳細資訊的,而圖的搜尋和資料探勘在開始時是不需要這些節點的詳細資訊,而是在挖掘到了有用的資訊時才從關係表中獲取每個節點的詳細資訊。所以在進行搜尋或者其他的圖挖掘的時候完全不需要知道節點詳細資訊,而是隻要拿到每個節點的唯一編號就行了,當需要時再根據這個編號到節點關係表中獲取節點的資訊,這樣做可以減少圖所佔用的記憶體,因為此時每個節點只是一個數字,而不是那些複雜的資訊。廢話不多說,那麼如何根據邊關係表得到圖呢?還原圖其實只需選擇一個節點出發,對圖進行探索就行了。如此處選擇編號為1的節點(此後將以節點編號表示一個節點)對圖進行探索:可以根據上面的表知道和1相連的節點有3、5和6,那麼就存在1——>3,1——>5和1——>6(此時是找以1為起始節點的邊),可以知道現在圖的結構已經探索到了3、5和6節點,那麼接下來將對3、5和6進行探索,即獲取以3為起始節點、5為起始節點和6為起始節點的邊,依次類推,將構造出一個圖的結構。大家可能都看得到,其實上面的3、5和6都是1的鄰接節點,所以可以推出:一個鄰接節點將產生一條邊(此處的鄰接節點是和節點直接相連的節點,並且可達,如是有向邊,這就要考慮方向性,反向是不可達的,所以此時不存在相互性),所以圖的邊可以直接更具節點的鄰接節點來進行儲存,這樣可以簡化圖的還原。大家可能發現這樣通過資料庫來對圖進行擴充套件是非常漫長的,如果圖有上百萬個節點,那麼下個要通過這樣的資料庫來進行還原圖那是非常艱苦的。下面介紹一種相對比較好的儲存方式。

      2)關係資料庫+文字

       此種方法就是將節點的詳細資訊儲存到資料庫中,所以還使用上面的節點關係表,而此處的邊就不能儲存在資料庫中了,而是儲存在文字中,此處就不對節點儲存進行詳細的介紹了。上面最後說過一個節點和其鄰接節點就會構成一條邊,所以此處就是通過儲存鄰接節點來對邊進行儲存了。我們是將每個節點的鄰接節點通過陣列寫到文字中,可知一個節點的鄰接節點不止一個,所以每個節點的鄰接節點是儲存在文字中的某一塊區域,所以此處需要引入偏移量的概念,此處每個節點對應了一個偏移量,這個偏移量是做什麼用的呢?就是指出這個節點的鄰接節點資訊是儲存在文字的那個位置開始。同時可以知道一個節點的鄰接節點個數是和該節點的度有關的,例如上面的1節點有3個度,那麼1將有3個鄰接節點,所以將產生3條邊,這是一個重要的概念,因為度的大小和一個節點的鄰接節點個數相同,同時也影響該節點在儲存鄰接節點文字所佔據的大小。說了這麼多肯定會暈的,下面還是舉個例子說明吧:
鄰接節點文字
位置 鄰接節點
0 3
1 5
2 6
3 3
4 5
5 1
6 2
7 4
8 3
9 6
10 1
11 2
12 1
13 4
節點度文字
節點編號
1 3
2 2
3 3
4 2
5 2
6 2
鄰接節點偏移量
節點編號 偏移量
1 0
2 3
3 5
4 8
5 10
6 12

          此處可以看出,1的鄰接節點是儲存在鄰接節點文字的0位置到2的位置,2的鄰接節點是儲存在3位置到4的位置.....其他的節點也可以以此退出,其實在文字中儲存是以陣列儲存的,並沒有上面那樣的結構,如鄰接節點文字:[3,5,6,3,5,1,2,4,3,6,1,2,1,4],在文字中每個數字一行,而偏移量就是某個節點的鄰接節點儲存位置的起始位置,而長度為該節點的度的大小,同樣節點的度和偏移量也是這樣儲存的,也是每個陣列一行,同時行數和節點的編號要對應,如1節點是第一行,2節點是第二行....因為這些值是和節點一一對應的。在我們的程式中其實是將這些資訊通過IO讀到陣列中,如我們定義一個adjancent[]陣列用於存放鄰接節點的,adjancentoffset[]儲存偏移量的,degree[]是儲存節點度的。如1節點的度是degree[0],它的鄰接節點偏移量是為:adjancentoffset[0],那麼1節點的鄰接節點是儲存在adjancent[adjancentoffset[0]]到adjancent[adjancentoffset[0]+degree[0]-1]中,那麼就會產生相應的邊,那麼邊的編號就是adjancentoffset[0]~adjancentoffset[0]+degree[0]-1,可以看到邊的編號和鄰接節點的儲存位置是對應的,因為一個鄰接節點對應了一條邊,上面已經講過,此處就不在贅述。我們就可以將這些陣列存放在程式中,並利用這些陣列還原圖結構,例如:我們還是以1節點開始擴充套件圖:1的鄰接節點有3、5和6,此時就擴充套件了三個節點,在通過這三個節點擴充套件它們各自的鄰接節點,依此類推,邊還原了圖的結構,該種方法,避免了大量的資料庫的訪問,而是通過把圖儲存在文字中,並一次性的讀入到記憶體中,並通過迭代還原圖結構。但這種操作容易產生幾種缺陷,第一、圖的資訊更新不方便,應為向圖中添加了一些節點,那麼就要重新生成這些文字,第二、這些圖的資訊全部儲存在記憶體中,使得圖的大小收到記憶體的限制。我做試驗的時候,儲存2百萬個節點2百多萬條邊的圖佔記憶體20多M。所以多餘圖的節點個數不怎麼更改,圖的節點個數不不億量級的可以採取這樣的方式儲存。關於該種方法的使用詳細見
《一種圖儲存結構【看了之後你會對圖的結構有新的認識》
       此文到此已差不多結束,希望如有什麼不對的地方洗完指出!歡迎評論該文!        謝謝瀏覽!此文完!