1.塊狀鍊錶的基本思想
常見的線性表結構修改操作有:再某一位置後插入一段數,從某一位置開始刪除連續若干個數,我們不妨先來看看陣列和鍊錶這兩種常用線性結構的實現效果。
可見,它們各有各的優勢和缺點,且恰巧是優勢互補。我們不禁想,如果把兩者結合起來,是不是會有更優異的表現?塊狀鍊錶正好是基於這個思想,將陣列和鍊錶結合了起來。塊狀鍊錶整體上看其結構是乙個鍊錶,鍊錶上每個節點存放著一段陣列,鍊錶上每個節點的資料拼接起來就是原先的整個線性表的內容,「塊狀」一詞由此而來。
塊狀鍊錶的基本組織形式,假設鍊錶中每個節點所維護的陣列的大小為s,那麼,一共需要維護c快,滿足sc=n(為了計算方便,如果n不是s的倍數,不妨在最後補齊相應數量的空位),n為要維護的元素總個數。按照這種方式分塊,我們來看一下塊狀鍊錶在上述三種操作中的表現。
(1)定位:定位時需要沿著鍊錶的指標依次查詢。假設查詢陣列中第p個數,那麼需要找到塊bt,使得tss>=p。所以,查詢的時間複雜度與塊數同階,為o(c)。當然,你也許會像維護乙個反向的索引,即在外部用陣列維護鍊錶節點的順序,這樣就可以二分查詢了。不過由於塊狀鍊錶是動態的,每次修改後這個陣列又需重新維護,維護這個陣列的時間複雜度仍然是o(c)。
(2)插入:插入時間顯然與插入的數的個數有關,為了考察塊狀鍊錶本身,我們忽略這一點。首先,需要花費o(c)的時間定位到要插入的位置,接下來插入的主要時間消耗**於塊的**———因為大多數情況會在塊內某處插入,而**的時間複雜度與塊的大小相關,即o(s)。
(3)刪除:同樣先花費o(c)的時間定位,如果整塊被刪除,那麼只需要o(1)的時間,而塊的一部分被刪除的話,我們就需要把塊**,這一步的時間複雜度同樣與 塊的大小相關,為o(s).
綜上所述,插入與刪除的時間複雜度仍然為o(s+c),sc=n,由基本不等式可知。當s=c=n的1/2的時候,s+c取得最小值。故理論上,塊狀鍊錶的插入和刪除操作的時間複雜度均為o(n的1/2),那麼,我們如何在插入,刪除等操作之後仍然保持每塊大小約為n的1/2呢?以及針對於此的維護操作又有怎樣的時間複雜度呢?
2.塊狀鍊錶的基本操作
為了使得塊狀鍊錶每次插入和刪除操作的時間複雜度為理論最優值o(n的1/2),我們要保證塊的大小在一定範圍內。我們一般維持每個塊的大小s在區間[(n的1/2)/2,n的1/2]之中,這樣,塊數c也在區間[n的1/2,2n的1/2]中,因此塊狀鍊錶不會退化。本文中,我們採用另外一種方式來維持這種性質:保證任何相鄰兩塊的大小加起來大於n的1/2,並且每塊大小不超過n的1/2,這種方法能保證塊數c在區間[n的1/2,2n的1/2]之中(簡要證明:當每塊大小為上限值n的1/2時,塊數c取得最小值n的1/2;若任意相鄰兩塊大小之和大於n的1/2,那麼我們將所有塊兩兩分組,即塊0和塊1一組,塊1和塊2一組…那麼至多不會超過n的1/2組,又因為每組至多有兩塊,故總塊數不會超過2n的1/2).之所以選擇這種方式,是因為考慮到**實現的方便,因為在這種實現方式中就不需要考慮塊過大而需要**的情形。當然,實現方式因人而異,讀者可以選擇適合自己的最好方式。
在介紹操作之前,我們首先對即將用到的一些變數表示做乙個約定:
next域:維護鍊錶節點的下乙個位置
cursize域:維護鍊錶節點當前陣列中元素的個數
data域:維護要儲存的資料。
塊狀鍊錶模板
塊狀鍊錶 下標從0開始 塊大小和塊數設為比sqrt n 稍大 const int n 2000000 10,block sz 4000 100,block num 4000 10 queue que int head char str n struct block g block num int n...
塊狀鍊錶(STL rope)
塊狀鍊錶 stl rope 首先介紹一下塊狀鍊錶。我們都知道 陣列 具有 o 1 的查詢時間,o n 的刪除,o n 的插入。鍊錶 具有 o n 的查詢時間,o 1 的刪除,o 1 的插入。既然陣列和鍊錶各有優劣,那麼我們為何不將鍊錶和陣列組合起來,一起來均攤時間呢?做法就是維護乙個鍊錶,鍊錶中的每...
塊狀鍊錶全紀錄
塊狀鍊錶的簡單介紹 塊狀鍊錶,可以說是一種很犯規的資料結構 支援動態的序列加入刪除,詢問區間和之類的操作 同時擁有陣列和鍊錶的優點 陣列 所有資料在記憶體中是緊湊儲存的,優點是定位快 o 1 鍊錶 通過指標將不同位置的元素鏈結起來 修改快 o 1 總的來說重要操作只有幾個 定位,插入,合併 塊狀鍊錶...