闲谈StringBuilder
? 大家都知道StringBuilder在拼接大量字符串的時候相對String來說具有很高的效率,這是由于StringBuilder在內部處理上使用了字符串的鏈式存儲表示法(串的塊鏈存儲法)。串的塊鏈存儲結構的C代碼是這樣的:
#define CHUNKSIZE 80typedef struct Chunk
{
char ch[CHUNKSIZE];
struct Chunk* next;
}Chunk;
??由此,可以看到它同時具有數組和鏈表的特性。我們可以類比的想象一下,把上面的代碼改寫成下面的C#代碼:
class StringBuilder{
private char[] ch;
private StringBuilder next;
}
? 其實上面的這段C#代碼就是StringBuilder的一部分定義了,但StringBuilder中為了快速的獲取到字符串的長度以及更方便的輸出字符串,它保存了一個Offset字段,這個字段記錄了所有后繼結點(next)里ch的長度之和。明顯頭結點ch中字符的長度(非數組長度)與這個offset的和就是整個字符串的長度Length,這樣顯得更高效避免了遍歷字符串求長度的開銷。
? 當我們初始化StringBuilder的時候,在構造函數中允許我們傳入capacity、maxcapacity以及string參數,capacity就是我們這里ch數組的長度,而maxcapacity是最大的可容下的字符串長度,也就是說Length的長度必須小于maxcapacity。隨便說一句,capacity和maxcapacity的默認值分別是16和2147483647。
? 說了那么多原理性的東西,下面來看看一段使用StringBuilder添加字符串的代碼,后面,我會使用圖文來解析StringBuilder內部的工作方式。
var strb = new StringBuilder("abcdefghijklm");//chuncksize=16,目前還有3個空閑var input=Console.ReadLine();
strb.Append(input);
? 下面我們分輸入的情況來討論:
1.如果input的長度小于等于3:
?? 當strb的內部發現當前Append的字符串長度小于strb中chunck中剩余的長度,就會直接將輸入字符串添加到末尾。
?
2.如果input的長度大于3:
? 如果input的長度大于strb中ch剩余長度的時候,那么就要對strb進行“斷裂”了,也就是說將input前一部分的值放到strb中去,同時將input剩下的值放到新創建的StringBuilder(也就是next)當中。
?
?
? 請注意strb中和strbNew中的藍色部分,這不是巧合相等,它們確實是相等的長度,在“斷裂”后,系統會重新為strb分配存儲空間,這個存儲空間中空閑的部分恰恰就是沒有斷裂前chunck中的長度。我還必須說明的一點是,在“斷裂”過后,還會重新設置strb的offset,這個offset實際上就是strbNew的長度而且這個是一個循環遞歸的過程,在下一次strb滿的時候又會執行整個這個過程。
? StringBuilder的整個過程就是一個串的塊鏈存儲法的實現,它也用到了數組拷貝,但是它是通過unsafe代碼來實現的,所以性能相對于托管代碼要高一點。
轉載于:https://www.cnblogs.com/GardeniaPeter/archive/2011/12/14/2287584.html
總結
以上是生活随笔為你收集整理的闲谈StringBuilder的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: StringBuffer
- 下一篇: 开始 Sencha Touch 2 之旅