Gap Buffer 簡潔有效的文字編輯演算法

2021-10-23 16:18:06 字數 2262 閱讀 3646

在對jetpack compose原理進行分析過程中,了解到它的狀態儲存使用的乙個叫gap buffer的資料結構,開始的時候不太清楚這個是什麼演算法,準備進行深入了解下,了解後才發現這個演算法很早就接觸過,之前在做過一道文字編輯器的演算法題的時候,使用的就是這種演算法,今天就來講解下這個演算法以及分析jetpack compose為何使用這種演算法進行狀態儲存。

實現文字編輯器的時候我們會考慮,如果使用鍊錶的話,插入可以在o(1)的複雜度完成,但是如果游標隨機移動的話,查詢的話則需要o(n)的複雜度,如果使用陣列的話,查詢可以在o(1)的複雜度快速完成,但是插入的話則需要o(n)的複雜度。兩者就像魚和熊掌一樣,不可兼得。如何解決這種矛盾,是實現文字編輯器的關鍵,其實有很多演算法都可以取得不錯的效果,比如塊狀鍊錶(可以在o(n^1/2)複雜度完成插入和查詢)、rope樹(一種平衡查詢樹)、piece table(改進版本的gap buffer,微軟doc就是使用的這個演算法,同時可以快速實現撤銷和重做)。不過今天我們的重點是gap buffer演算法,接下來我們就主要分析下gap buffer(gap buffer是notepad++採用的演算法)。

我們來分析下文字編輯器的特點,我們的插入都是在游標處進行的,如果我們在陣列的游標處預留一段空白位置,我們把它叫做buffer,這樣插入的話我們就可以在o(1)的複雜度來完成,如果游標移動到其他位置的話,我們也可以在o(1)的複雜度完成(只是進行移動,不在游標處進行插入),如果游標移動到新的位置並且需要進行插入的時候,我們則需要將空的buffer移動到新的游標位置,這個操作的話需要o(n)的複雜度才能完成(不過對於實際的文字編輯過程,連續的插入遠遠大於移動游標的頻率),如果在某個位置空白的buffer位置不夠了,我們需要對其進行擴容,這個操作同樣需要o(n)的複雜度,因此buffer的size選取也要根據實際情況靈活確定。因此我們就得到了乙個能夠在大多數情況下都能在o(1)的複雜度完成文字編輯器所需要操作的演算法,並且這個演算法還是如此簡潔便於實現。

我們來簡單的模擬上訴演算法流程,假如我們目前文字編輯器內容為"hello,world,游標所在位置為5,buffer size 我們選取5,此時陣列內容如下(「|」代表游標位置,「_」代表空白buffer)

hello,|_____world
我們此時連續輸入my,陣列將變成這樣

hello,my|___world
這時我們移動游標到w位置處,

hello,my___w|orld
由於還沒有執行插入操作,因此此時buffer位置沒有變化,這時我們插入m

hello,mywm|____orld
我們在插入的之前,將buffer移動到w後面,同時更新buffer size 為5(這個可以根據具體情況進行處理,也可以不更新),然後插入m

經過上訴分析,我們發現實現gap buffer需要以下資料結構,乙個陣列,乙個指標表示游標即(gap開始的位置),同時還需要gapsize 表示buffer的大小,我們還需要實現四個操作,插入刪除字元、查詢移動游標、移動buffer位置、擴容,簡單的**如下(沒法編譯,請不要直接拷貝)

int gap_size =5;

struct gapbuffer gapbuffer;

//插入字元

void

insert

(char c)

gapbuffer.array[

++gapbuffer.gapstart]

=c;--gapbuffer.gapsize;

++len;

}//擴容

void

expanison()

//移動gap,這個實現不會擴容buffer

void

movegap

(int pos)

void

arraycopy

(char array,

int srcsatrt,

int dststart,

int len)

**如果直接看的話可能不好理解,但是自己在腦子裡過一遍,自己想下陣列拷貝的位置和大小,應該就能理解了

了解了gap buffer 之後,我們現在再來看jetpack compose為何使用gap buffer來儲存狀態,我們知道ui本質是一顆樹形結構,ui的布局測量渲染都是對樹進行深度遍歷,對於每個元件的狀態儲存,我們可以看成是插入字元,而對於每個元件的遍歷,我們可以看成是游標移動,因此jetpack compose使用此演算法來儲存狀態(不過這裡我比較疑惑的是,為何jetpack compose不採用其他框架使用的樹形結構)。

簡潔的優勢

簡潔的優勢 大腦只能理解簡單的東西 在這個世界中,複雜的問題都要轉換為簡單的東西來解決。因為很顯然,我們的思維只能理解最簡單的東西,而複雜的思維實際上只是簡單的步驟的疊加。這一點,在數學中最明顯,無論怎麼複雜的證明,都可以歸結為一些簡單的邏輯,而困難在於把這些簡單的東西串連起來。評注 我也沒有想清楚...

簡潔的資料結構

資料結構在計算機科學界至今沒有標準的定義。個人根據各自的理解的不同而有不同的表述方法 sartaj sahni在他的 資料結構 演算法與應用 一書中稱 資料結構是資料物件,以及存在於該物件的例項和組成例項的資料元素之間的各種聯絡。這些聯絡可以通過定義相關的函式來給出。他將資料物件 dataobjec...

簡潔的ios小介面

下午寫寫了個小東西小介面 有需要的可以直接拿過來用 簡潔,挺好看,自我感覺 寫介面其實就是自上而下的在view加空間,注意一下位置就行了 id initwithframe cgrect frame return self 以上就是第乙個頁面的所有內容 我們來看一下第二張圖吧 xib 中新增控制項實現...