C#集合

來源:互聯網
上載者:User

StringBuilder竟然是基於鏈表而不是數組的集合,它不是2被的增加容量,而是新增一個StringBuilder節點,容量為int num = Math.Max(minBlockCharCount, Math.Min(this.Length, 8000));minBlockCharCount:填滿上個節點後剩餘的字元個數;this.Length:上兩個節點的容量之和新增的資料往裡面填,基本上每個節點的最大容量就是8000個字元,滿了之後再新增節點,不會拷貝以前的資料。StringBuilder有一個名為m_ChunkPrevious的欄位,指向上一個節點。不知道這是新的實現方式還是以前就是這樣實現的,
對於一直往裡面Append資料效率的確是快了,不會拷貝以前的資料,其他的操作實現起來就麻煩一點,至於效率估計會有點影響。這樣的實現方式對於添加大量的字串效率會有很大的提高,如果是用一個連續的數組存放字串的話,在複製資料的時候效能會有點影響。

 

String關於字串,我想大家最喜歡比較+、+=、String.Format、String.Concat隨的效能好,如果只是一條或是少量順序語句,說誰的效能好沒有任何意義,根本體現不出誰的效能好,要比效能就得大量的資料測試,在迴圈次數相同的情況下,他們幾個的效能真的差不多,如果非要比速度的話,”+”>“+=“>“ConCat”>“Format”並不是大家常說的+=的效能比+好(不一定總是這個結果)。其實要提高效能就得減少迴圈的次數,在以同樣的方式減少迴圈的次數的情況下,效能提高了,基本上是效能跟迴圈的次數成反比,效能差不多。我們來看看他們的彙編代碼就知道了,我們看出+與+=執行的指令條數是一樣的,ConCat比Format少了幾個移動指標的指令,其他的指令個數都是一樣的,當然他們的記憶體回收次數也就是一樣的。總之少量字串用他們哪一個都無所謂,畢竟不涉及效能問題,我喜歡用Format,因為它讓代碼更好理解,看著舒服些,大量字串就必須得用StringBuilder。


測試代碼:
View Code

  static void Test1()        {            int timer = 100000;            using (new OperationTimer("+="))            {                string s1 = string.Empty;                for (int i = 0; i < timer; i++)                {                    s1 += i.ToString();                }            }            using (new OperationTimer("+"))            {                string s1 = string.Empty;                for (int i = 0; i < timer; i++)                {                    s1 = s1 + i.ToString();                }            }            using (new OperationTimer("concat"))            {                string s1 = string.Empty;                for (int i = 0; i < timer; i++)                {                    s1 = string.Concat(s1, i.ToString());                }            }            using (new OperationTimer("format"))            {                string format = "{0}";                string s1 = string.Empty;                for (int i = 0; i < timer; i++)                {                    s1 = s1 + string.Format(format, i.ToString());                }            }        }        static void Test2()        {            int timer = 110000;            using (new OperationTimer("+"))            {                string s1 = string.Empty;                for (int i = 0; i < timer; i+=2)                {                    s1 = s1 + i.ToString()+(i+1).ToString();                }            }            using (new OperationTimer("+="))            {                string s1 = string.Empty;                for (int i = 0; i < timer; i += 2)                {                    s1 += "i" + i.ToString() + (i + 1).ToString();                }            }             using (new OperationTimer("concat"))            {                string s1 = string.Empty;                for (int i = 0; i < timer; i += 2)                {                    s1 = string.Concat(s1, i.ToString(), (i + 1).ToString());                }            }            using (new OperationTimer("format"))            {                string format = "{0}{1}";                string s1 = string.Empty;                for (int i = 0; i < timer; i += 2)                {                    s1 = s1 + string.Format(format, i.ToString(), (i + 1).ToString());                }            }        }

 

彙編代碼如下:

測試結果:

 

ArrayList你可以拋棄它了,用List吧,向ArrayList中添加實值型別資料的資料效能沒有List的好,參考型別效能差不多。實值型別ArrayList會出現裝箱和拆箱,效能差點,而參考型別大家調用的都是指標,List就別認為自己長得帥了,List會為每種實值型別都會產生一套代碼,而參考型別是同一套代碼。其實以前我也不知道為什麼會是這樣,在我看了C++的模版後我就明白了,模版的參數可以是任何類型,為每種類型產生一套代碼,但是C++有模版半特化功能,就是將模版的參數加一個約束,這種模版的參數必須是指標類型,有了這兩個模版,實值型別的就會調用第一個模版,產生一套代碼,因為每種實值型別所佔用的位元組不是都一樣,指標類型的就會調用特化的模版,因為每種指標佔用的都是4個位元組,所以根本不需要為每種類型都產生一套代碼。代碼的膨脹問題就是這樣解決的。List容量基本上是2倍2倍的擴增,然後將以前的資料複製過來,實值型別直接複製資料,參考型別直接複製對象的引用,如果對象被修改了,List中的引用也就被修改了,當然參考型別都是這樣的。

 

Hashtable也是過時了,被Dictionary取代了,非泛型的集合肯定是會被泛型的取代的。他們的實現原理我想應該是差不多的,對於雜湊字典,我認為瞭解他是怎麼散列的就行,每種集合的提共的方法其實都是都差不多,只是最主要的演算法不同而已。Object有個GetHashCode()方法,這個方法能為每個對象產生一個不同的長度為10的整數,然後將這個數散列到一個數組中,數組是按照質數的順序擴充的,也就是說,數組的長度都是質數,這主要是為了均勻的散列。如果向Dictionary中添加兩個相同的Key,也就是散列到同一個位置就會跑出異常, HashSet也是基於散列的,當有多個對象散列到同一個地方的時候,它不會跑出異常,而是直接返回。排除一個數組或是多個數組中的重複資料用HashSet是個不錯的選擇。

 

Stack棧很簡單,以2倍的方式擴容,進棧的相當於填充數組,從0~N-1,出棧的時候將最後加入棧中的元素清掉,也就是後進先出。

 

Queue隊列也很簡單,預設以2被的方式擴容,擴容的倍數可以自訂,進隊列的時候相當於填充數組,從0~N-1,出隊列就是返回一個索引所知的元素,每有一個元素出隊列,這個索引就增1,出隊列的元素清除,元素佔用的位置保留,即數組的大小不變,只是你訪問不了。

 

SortDictionary是基於紅/黑樹狀結構的,這個紅/黑樹狀結構還有點難理解,還在學習中,就不多說了。那就是尋找速度快,時間複雜度為O(logN),在添加元素的時候會經常調整樹的結構。

 

作者:陳太漢

部落格:http://www.cnblogs.com/hlxs/

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.