前向星與鏈?zhǔn)角跋蛐?/h2>

2018-06-18


今天學(xué)習(xí)了前向星這種數(shù)據(jù)結(jié)構(gòu),前向星是一種非常節(jié)省空間的存圖方式,在ACM比賽中,常見的的存圖方式有三種。


——鄰接矩陣,即用二維數(shù)組實(shí)現(xiàn),G[u][v]為<u,v>邊的權(quán)值。鄰接矩陣適用于存儲(chǔ)稠密圖,點(diǎn)不多而邊很多的時(shí)候,鄰接矩陣的優(yōu)點(diǎn)是好寫,可讀性高,方便刪除邊。

——鄰接表,一般用vector<edge>G[MAXN_V]模擬鄰接表,鄰接表適用于疏密圖,相比于鄰接矩陣節(jié)省空間。

其優(yōu)點(diǎn)是寫起來快,可讀性高,方便執(zhí)行STL中的一些函數(shù)。

——前向星,前向星是一種特殊的邊集數(shù)組,我們把邊集數(shù)組中的每一條邊按照起點(diǎn)從小到大排序,如果起點(diǎn)相同就

按照終點(diǎn)從小到大排序,并記錄下以某個(gè)點(diǎn)為起點(diǎn)的所有邊在數(shù)組中的起始位置和存儲(chǔ)長度,那么前向星就構(gòu)造好了.

用len[i]來記錄所有以i為起點(diǎn)的邊在數(shù)組中的存儲(chǔ)長度.,用head[i]記錄以i為邊集在數(shù)組中的第一個(gè)存儲(chǔ)位置.


我們輸入邊的順序?yàn)?

1 2? ? 2 3? ? 3 4? ? 1 3? ? 4 1? ? 1 5? ? 4 5

pair<int,int>G[MAXN_E];

用pair存儲(chǔ)并排序后得到

G[0]=(1,2);?

G[1]=(1,3);

G[2]=(1,5);

G[3]=(2,3);

G[4]=(3,4);

G[5]=(4,1);

G[6]=(4,5);


則head數(shù)組和len數(shù)組為:

head[1]=0;? head[2]=3;? head[3]=4;? ? head[4]=5;? ? head[5]=-1;

len[1]=3;? ? ? len[1]=3;? ? ? len[3]=1;? ? ? ? len[4]=2;? ? ? ? len[5]=0;


但是利用前向星會(huì)有排序操作,如果用快排時(shí)間至少為O(nlog(n))

——如果用鏈?zhǔn)角跋蛐?加入next索引模擬指針指向下一個(gè)點(diǎn)的位置,就可以避免排序.

建立結(jié)構(gòu)體為:

struct edge

{

? ? int to;//邊的終點(diǎn)

? ? int value;//邊的權(quán)值

? ? int next;//表示與第i條邊同起點(diǎn)的下一條邊的存儲(chǔ)位置

};

另外還有一個(gè)數(shù)組head[],它是用來表示以i為起點(diǎn)的索引的第一條邊存儲(chǔ)的位置,實(shí)際上你會(huì)發(fā)現(xiàn)這里的第一條邊存儲(chǔ)的位置其實(shí)

在以i為起點(diǎn)的所有邊的最后輸入的那個(gè)編號(hào).

如果按照索引順序,next表示下一條邊的存儲(chǔ)位置,如果按照添加順序,next即為上一條添加的邊的位置。

所以我們可以得到,輸入順序和存圖順序或者說是遍歷順序是相反的。

還是上面的圖,我們定義全局變量int cnt=0;

并將head[]初始化為-1;

void addedge(int u,int v,int w)

{

? ? e[cnt].value=w;

? ? e[cnt].to=v;

? ? e[cnt].next=head[u];

? ? head[u]=cnt++;

}

模擬插入為下面的過程:

edge[0].to = 2;? ? edge[0].next = -1;? ? ? head[1] = 0;

edge[1].to = 3;? ? edge[1].next = -1;? ? ? head[2] = 1;

edge[2].to = 4;? ? edge[2],next = -1;? ? ? head[3] = 2;

edge[3].to = 3;? ? edge[3].next = 0;? ? ? head[1] = 3;

edge[4].to = 1;? ? edge[4].next = -1;? ? ? head[4] = 4;

edge[5].to = 5;? ? edge[5].next = 3;? ? ? head[1] = 5;

edge[6].to = 5;? ? edge[6].next = 4;? ? ? head[4] = 6;


這樣在遍歷時(shí)是倒著遍歷的,也就是說與輸入順序是相反的,不過這樣不影響結(jié)果的正確性.

比如以上圖為例,以節(jié)點(diǎn)1為起點(diǎn)的邊有3條,它們的編號(hào)分別是0,3,5? 而head[1] = 5

我們?cè)诒闅v以u(píng)節(jié)點(diǎn)為起始位置的所有邊的時(shí)候是這樣的:

for(int i=head[u]; ~i ;i=edge[i].next)

那么就是說先遍歷編號(hào)為5的邊,也就是head[1],然后就是edge[5].next,也就是編號(hào)3的邊,然后繼續(xù)edge[3].next,也

就是編號(hào)0的邊,可以看出是逆序的.

鏈?zhǔn)角跋蛐堑膬?yōu)點(diǎn):比鄰接表還省空間,可以解決某些卡空間的問題,刪除邊也很方便,只需要更改next指針的指向即可。

總結(jié):根據(jù)圖的疏密選擇存儲(chǔ)方式,一般情況下用鄰接表,卡空間時(shí)間這些要求比較高的題目或者需要?jiǎng)h除邊操作的用鏈?zhǔn)角跋蛐恰?/b>

——本文部分地方引用了acdream大牛的文章。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容