塊狀鏈表基本操作及相關例題

部分內容參考自 論文 蘇煜《對塊狀鏈表的一點研究》

1. 數組和鏈表對比:

數組和鏈表對比
操作 數組 鏈表

存儲結構

地址連續的存儲單元,物理位置相鄰

地址不連續,物理位置不相鄰

定位

O(1)

O(N)

添加

O(N)

O(1)

刪除

O(N)

O(1)

數組有很好的定位功能,一般對應於固定的長度,不適合添加/刪除等操作,當數組有序時,可二分查找某值,效率很好,O(logN)。

鏈表添加刪除效率極高,很適合這類操作。但定位效率很低。

2.塊狀鏈表

塊狀鏈表是對數組和鏈表的折中,集兩者之長,在定位,添加刪除的效率上都有大幅提升。

整體上使用鏈表,鏈表節點是一個大小適當的數組。

如下圖:

3.基本操作

①:定位

從鏈表頭開始往後掃,每個節點記錄本節點合法數據的長度,最終會定位爲某一個塊及塊內偏移。

②:分裂

將指定的塊在指定的位置分裂成2個塊。

③:合併

本塊合併掉之後的那一塊,前提是2塊的有效數據長度之和 <= N (array的長度)

定位,插入,刪除的時候對本塊進行合併將會減少塊元素過少,否則有可能退化成普通的鏈表。

④:插入

在指定位置分裂,然後在本塊後面插入若干個塊,示意圖如下:

⑤:刪除

在指定的位置分裂,刪除本塊之後的若干塊,示意圖如下:

4.效率分析:

設數組大小爲x,數據總數爲N,則理想狀況下分塊樹爲N/x,則定位的時間複雜度爲O(N/x),插入刪除的時間複雜度爲O(x)

令N/x = x , x = sqrt(N),即每次操作的時間複雜度大致爲O(sqrt(N))

和平衡樹O(logN)等相比還是有較大差距,但是其附加空間很少,僅爲O(sqrt(N)),平衡樹的附加空間爲O(N)。

5.幾道例題:

①:NOI2003 editor(經典)

【題目大意】

一些定義:

文本:由0個或多個ASCII碼在閉區間[32, 126]內的字符(即空格和可見字符)構成的序列。

光標:在一段文本中用於指示位置的標記,可以位於文本首部,文本尾部或文本的某兩個字符之間。

文本編輯器:爲一個包含一段文本和該文本中的一個光標的,並可以對其進行如下六條操作的程序。如果這段文本爲空,我們就說這個文本編輯器是空的。

操作名稱

輸入文件中的格式

功能

MOVE(k)

Move k

將光標移動到第k個字符之後,如果k=0,將光標移到文本開頭

INSERT(n, s)

Insert n¿

S

在光標處插入長度爲n的字符串s,光標位置不變,n ³ 1

DELETE(n)

Delete n

刪除光標後的n個字符,光標位置不變,n ³ 1

GET(n)

Get n

輸出光標後的n個字符,光標位置不變,n ³ 1

PREV()

Prev

光標前移一個字符

NEXT()

Next

光標後移一個字符

比如一個空的文本編輯器依次執行操作INSERT(13, “Balanced tree”)MOVE(2)DELETE(5)NEXT()INSERT(7, “ editor”)MOVE(0)GET(16)後,會輸出“Bad editor tree”。

你的任務是:

建立一個空的文本編輯器。

從輸入文件中讀入一些操作並執行。

對所有執行過的GET操作,將指定的內容寫入輸出文件。

ps:這些操作僅僅是定位,添加,刪除,採用塊狀鏈表可以輕鬆搞定,splay等各種也可以。

有興趣的可以在下oj上測試下自己的代碼:

http://zerojudge.tw/ShowProblem?problemid=a105

②:反轉序列

【題目大意】

一個長度爲 n 的整數序列初始時從左到右爲1,2,3,……,n,現在對這個序列進行 m 次操作,每次把 p 到 q 的子序列反轉
求最後的序列

ps:操作很簡單,每次對一個區間進行反轉,求若干次反轉之後的序列。

這裏需要在每個節點維護一個域rev,rev=true代表本區間需要反轉,false表示不需要反轉

在區間合併、分裂以及最後的輸出上需要維護rev,操作很簡單,反轉該區間的值即可。

在反轉若干的區間的時候問題等價於將鏈表反轉。

有興趣的可以在下oj上測試下自己的代碼:

http://cstest.scu.edu.cn/soj/problem.action?id=3035


ps:用一個數組維護每一塊的長度,查找時可以二分,添加、刪除時採用順序操作。

刪除是二分定位可以跳過中間的直接刪掉所有待刪除塊。

因爲移位效率低,用平衡樹來維護就捨本逐末了,目測效率也沒多大改進。

不過對於反轉序列來說,因爲不涉及添加刪除,效果還是可觀的。


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