字串去重 Redis中字串資料結構的底層實現

2021-10-12 21:20:09 字數 2552 閱讀 2360

一.介紹sds:

在redis中並沒有直接使用c語言的字串(以空字元結尾的字元陣列),而是構建了一種名為簡單動態字元(sds)的抽象型別,並且sds用作redis的預設字串。

在redis中乙個可以被修改的字串值都是用sds來表示這樣乙個字串值的,因此在redis中鍵值對的底層都是由sds來實現的。

舉例:如果客戶端執行命令:set msg "hello world",那麼redis將在資料庫中建立乙個新的鍵值對,其中

鍵值對的鍵是乙個字串物件,物件的底層實現是乙個儲存著字串"msg"的sds

鍵值對的值也是乙個字串物件,物件的底層實現是儲存著字串"hello world"的sds。

對於sds不僅用來儲存redis中的字串值,還被用作緩衝區(buffer):

aof模組中的aof緩衝區

客戶端狀態中的輸入緩衝區。

二.定義

每個sds.h/sdshdr結構表示乙個sds值:

struct sdshdr{

//記錄buf陣列中已使用位元組的數量

//等於sds所儲存字串的長度

int len;

//記錄buf陣列陣列中未使用位元組的數量

int free;

//位元組陣列,用於儲存字串

char buf;

例子如下圖:

上圖中定義了乙個redis字串,該字串存放的情況如上圖中。

sds遵循c語言字串以空字元結尾的慣例,儲存空字元的1位元組空間不計算在sds的len屬性中。並且為空字元分配額外的1位元組空間,以及新增空字元到字串末尾等操作都是由sds函式自動完成。這樣的乙個好處是可以重用c語言字串函式庫中的函式。

上圖的sds中並沒有分配未使用空間

下面為上圖中的redis分配未使用空間,如下圖:

圖中在redis字串後面新增了五個空位元組,這個五個位元組表示分配的未使用空間。因此free=5

2.1分析屬性 len

在sds中len屬性記錄sds的長度,所以獲取乙個sds長度的複雜度僅為o(1),這確保獲取字串長度的工作不會成為redis的效能瓶頸。

設定和更新sds長度的工作是由sds的api在執行時自動完成的,使用sds無需手動修改長度。

2.2杜絕緩衝區溢位

在平時初始化陣列時一般需要給陣列初始化一定的長度,那麼在sds中是如何保證buf(char陣列)的記憶體時足夠的呢?並且保證buf不會記憶體溢位的呢?

在sds中設定了一套空間分配策略,該策略完全杜絕了發生緩衝區溢位的可能性:

當sds api需要對sds進行修改時,api會先檢查sds的空間是否滿足修改所需要的要求,如果不滿足的話,api會自動講sds的空間擴充套件至執行修改所需的大小,然後才執行實際的修改操作,如果滿足則直接修改。因此使用sds不需要手動修改sds的空間大小,也不會出現緩衝區溢位的問題。

例如:我們使用sds api中的拼接字串函式sdscat拼接msg字串,那麼執行sdscat(msg,'cluster')

此時sds在執行sdscat(msg,'cluster')之前會檢查msg的長度是否足夠,如果msg目前的空間不足以拼接cluster,那麼sdscat會先擴充套件msg的空間,然後再去執行sdscat(msg,'cluster'),拼接完成後如圖

sdscat操作不僅對sds進行拼接操作,還會為sds分配13位元組的未使用空間(free=13),拼接後的字串長度是13,這就涉及到了sds的空間預分配策略。

2.3空間預分配策略

空間預分配策略主要用於優化sds的字串增長操作:當sds的api對乙個sds進行修改,並且需要對sds進行空間擴充套件時,此時會為sds分配額外的未使用空間。

空間預分配策略如下:

通過空間預分配策略redis可以減少連續執行字串增長操作所需的記憶體重分配次數。

2.4惰性空間釋放

惰性空間釋放主要用於優化sds的字串縮短操作,當sds的api需要縮短sds儲存的字串時,程式並不立即使用記憶體重分配來**縮短後多出來的位元組,而是使用free屬性將這些位元組的數量記錄起來,並等待以後使用。

例如通過sds api中的sdstrim函式來移除指定的字元,當執行sdstrim(msg,"cluster")後,sds並不會釋放cluster的7位元組空間,而是將這7個位元組保留在sds中,如果以後對sds進行增長操作,則這些空間就會排上用場。

2.5二進位制安全

在sds的buf陣列中儲存的並不是字元,而是儲存的一系列的二進位制資料,這樣就確保了redis可以適用各種不同的場景。

內容來自《redis設計與實現》黃健巨集著

字串右旋 字串去重

1.將n個字元的陣列,迴圈右移k位。時間複雜度o n 實現思路 兩種實現思路 1.借助輔助空間,按照後面的順序進行拷貝,最後拷貝回字串 2.三次反轉法就可實現 include void rotatekth char str,int size,int k 2.附加題 刪除小寫字母字串中重複字元。如果可...

字串去重

字串去重,思路是在乙個字串例如 strstrrtsiiiinnnggggg 中,遍歷所有的字元,拼接到stringbuffer中。在執行速度上來看stringbuffer的拼接速度要快與string。通過str.charat i 的方法得到當前遍歷到的字元。通過indexof方法得到該字元第一次出現...

字串去重

doctype html en utf 8 viewport content width device width,initial scale 1.0 document title head 思路 1.宣告乙個空字元 2.將需要去重字元,乙個乙個新增到空字串中 條件 s裡面沒有這個字元,就加進去 v...