c#資料結構之Array、ArrayList、List、LinkedList對比分析
一、前言:
在c#資料結構中,集合的應用非常廣泛,無論是做BS架構還是CS架構開發,都離不開集合的使用,比如我們常見的集合包括:Array、ArrayList、List、LinkedList等。這一些資料集合,在功能上都能夠實現集合的存取,但是他們內部有什麼區別,在使用時需要注意一些什麼呢?下面根據個人的經驗,對這一些集合資料的使用做一個簡單的小結,如果說的不對的地方,歡迎指出,多多交流改進。
二、Array集合簡介
Array集合,也就是陣列,是最簡單的資料結構,其儲存的資料在記憶體空間是連續的,陣列有一下一些特點
- 1.資料儲存是連續的
- 2.陣列長度在定義時就必須制定
- 3.陣列儲存的資料型別都是同一型別
- 4.陣列可以直接通過小標訪問
優缺點:
優點:
1、可以根據索引直接訪問,訪問速度快
2、資料是安全的,由於資料型別一致性,在儲存使用過程中不涉及
缺點:
1、由於資料是連續儲存的,導致插入效率變慢
2、由於陣列長度大小固定,那麼對預期非固定長度的數字不好處理
練習例項程式碼:
/// <summary> /// 陣列練習操作 /// </summary> public class ArrayTest { /// 陣列 Array 對於大家來說一點都不陌生 /// 陣列是在記憶體連續分配的儲存空間,這也導致陣列有一下一些特點 /// 1.資料儲存是連續的 /// 2.陣列長度在定義時就必須制定 /// 3.陣列儲存的資料型別都是同一型別 /// 4.陣列可以直接通過小標訪問 /// /// 優缺點: /// 優點: /// 1、可以根據索引直接訪問,訪問速度快 /// 2、資料是安全的,由於資料型別一致性,在儲存使用過程中不涉及到裝箱拆箱操作 /// 缺點: /// 1、由於資料是連續儲存的,導致插入效率變慢 /// 2、由於陣列長度大小固定,那麼對預期非固定長度的數字不好處理 /// int型別的陣列操作 public static void IntArrayTest() { //// 定義一個秒錶,執行獲取執行時間 Stopwatch st = new Stopwatch();//例項化類 st.Start();//開始計時 Console.WriteLine("開始初始化長度為10000000的int陣列:"); //// 定義一個數組 int[] nums = new int[10000000]; for (int i = 0; i < 10000000; i++) { nums[i] = 1 + 1; } //需要統計時間的程式碼段 st.Stop();//終止計時 Console.WriteLine(string.Format("初始化長度為10000的int陣列完畢!總耗時{0}毫秒", st.ElapsedMilliseconds.ToString())); } }
三、ArrayList集合簡介
ArrayList 是Array的升級版,能夠解決Array的一些缺點
ArrayList其內部實現也是Array,只是其長度是可以動態,在其內部用一個變數記錄控制長度,ArrayList有如下一些特點
- 1.長度不固定
- 2.可以儲存不同的資料型別(object)
- 3.同樣支援索引查詢(可以直接通過小標訪問)
- 4.靈活性更強,以犧牲效能為代價
優缺點:
優點:
1、長度不固定,在定義是不必擔長度溢位
2、可以儲存任意資料型別
3、可根據索引查詢,查詢效率快
缺點:
1、由於長度不固定,執行效率低下,因為超出預設長度(10)後,會自動擴容拷貝資料,犧牲效能
2、由於儲存型別是object,所以在存資料時會有裝箱操作,在取資料時會有拆箱操作,影響效率
3、執行緒不安全,因為其內部實現是用size、array來共同控制,在新增操作時是非原子操作,所以非安全執行緒
使用技巧:
在實際使用過程中,為了避免自動擴容,可以預估資料長度,初始化一個數據長度,從而提高效率
練習例項程式碼:
/// <summary> /// ArrayList陣列練習操作 /// </summary> public class ArrayListTest { /// ArrayList 是Array的升級版,能夠解決Array的一些缺點 /// ArrayList其內部實現也是Array,只是其長度是可以動態,在其內部用一個變數記錄控制長度,ArrayList有如下一些特點 /// 1.長度不固定 /// 2.可以儲存不同的資料型別(object) /// 3.同樣支援索引查詢(可以直接通過小標訪問) /// 4.靈活性更強,以犧牲效能為代價 /// 優缺點: /// 優點: /// 1、長度不固定,在定義是不必擔長度溢位 /// 2、可以儲存任意資料型別 /// 3、可根據索引查詢,查詢效率快 /// 缺點: /// 1、由於長度不固定,執行效率低下,因為超出預設長度(10)後,會自動擴容拷貝資料,犧牲效能 /// 2、由於儲存型別是object,所以在存資料時會有裝箱操作,在取資料時會有拆箱操作,影響效率 /// 3、執行緒不安全,因為其內部實現是用size、array來共同控制,在新增操作時是非原子操作,所以非安全執行緒 /// /// 使用技巧: /// 在實際使用過程中,為了避免自動擴容,可以預估資料長度,初始化一個數據長度,從而提高效率 /// ArrayList操作例項 public static void ArrayListOpert() { //// 定義一個秒錶,執行獲取執行時間 Stopwatch st = new Stopwatch();//例項化類 //// 需要統計時間的程式碼段(統計初始化長度時的執行時間) st.Start();//開始計時 Console.WriteLine(""); Console.WriteLine(""); Console.WriteLine("ArryList集合儲存資料量為10000000,初始化一個長度,執行開始:"); ArrayList arrayList = new ArrayList(10000000); //// 定義一個數組 for (int i = 0; i < 10000000; i++) { arrayList.Add(1 + 1); } st.Stop();//終止計時 Console.WriteLine(string.Format("ArryList集合儲存資料量為10000000,初始化一個長度,執行完畢:!總耗時{0}毫秒", st.ElapsedMilliseconds.ToString())); //// 需要統計時間的程式碼段(統計初始化非指定長度時的執行時間) st.Restart(); Console.WriteLine(""); Console.WriteLine("ArryList集合儲存資料量為10000000,初始化不指定長度,執行開始:"); arrayList = new ArrayList(); //// 定義一個數組 for (int i = 0; i < 10000000; i++) { arrayList.Add(1 + 1); } st.Stop();//終止計時 Console.WriteLine(string.Format("ArryList集合儲存資料量為10000000,初始化不指定長度,執行完畢:!總耗時{0}毫秒", st.ElapsedMilliseconds.ToString())); } }
四、List集合簡介
隨著c#泛型的推出,為了避免ArrayList一些缺點,微軟推出了List集合
List集合內部還是採用的Array實現,同時在定義時需要指定對應的資料型別
這樣級保留了Array集合的優點,同時也避免了ArrayList集合的資料型別不安全和裝箱帶來的效能犧牲
List特點:
- 1、資料長度不固定,自動增加
- 2、儲存相同的資料型別
- 3、可根據索引查詢,查詢效率快
優缺點:
優點:
1、長度不固定,在定義是不必擔長度溢位
2、儲存相同資料型別的資料,避免的資料的裝箱拆箱,提高了資料處理效率
3、支援索引查詢,查詢效率快
缺點:
1、由於長度不固定,執行效率低下,因為超出預設長度(10)後,會自動擴容拷貝資料,犧牲效能
2、執行緒不安全,因為其內部實現是用size、array來共同控制,在新增操作時是非原子操作,所以非安全執行緒
練習例項程式碼:
/// <summary> /// List練習操作 /// </summary> public class ListTest { /// 隨著c#泛型的推出,為了避免ArrayList一些缺點,微軟推出了List集合 /// List集合內部還是採用的Array實現,同時在定義時需要指定對應的資料型別 /// 這樣級保留了Array集合的優點,同時也避免了ArrayList集合的資料型別不安全和裝箱帶來的效能犧牲 /// List特點: /// 1、資料長度不固定,自動增加 /// 2、儲存相同的資料型別 /// 3、可根據索引查詢,查詢效率快 /// /// 優缺點: /// 優點: /// 1、長度不固定,在定義是不必擔長度溢位 /// 2、儲存相同資料型別的資料,避免的資料的裝箱拆箱,提高了資料處理效率 /// 3、支援索引查詢,查詢效率快 /// 缺點: /// 1、由於長度不固定,執行效率低下,因為超出預設長度(10)後,會自動擴容拷貝資料,犧牲效能 /// 2、執行緒不安全,因為其內部實現是用size、array來共同控制,在新增操作時是非原子操作,所以非安全執行緒 /// ArrayList操作例項 public static void ListOpert() { //// 定義一個秒錶,執行獲取執行時間 Stopwatch st = new Stopwatch();//例項化類 st.Start();//開始計時 //// 需要統計時間的程式碼段(統計初始化長度時的執行時間) Console.WriteLine(""); Console.WriteLine(""); Console.WriteLine("List集合儲存資料量為10000000,初始化一個長度,執行開始:"); List<int> list = new List<int>(10000000); //// 定義一個數組 for (int i = 0; i < 10000000; i++) { list.Add(1 + 1); } //需要統計時間的程式碼段 st.Stop();//終止計時 Console.WriteLine(string.Format("List集合儲存資料量為10000000,初始化一個長度,執行完畢:!總耗時{0}毫秒", st.ElapsedMilliseconds.ToString())); //// 需要統計時間的程式碼段(統計初始化非指定長度時的執行時間) st.Restart(); Console.WriteLine(""); Console.WriteLine("List集合儲存資料量為10000000,初始化不指定長度,執行開始:"); list = new List<int>(); //// 定義一個數組 for (int i = 0; i < 10000000; i++) { list.Add(1 + 1); } st.Stop();//終止計時 Console.WriteLine(string.Format("List集合儲存資料量為10000000,初始化不指定長度,執行完畢:!總耗時{0}毫秒", st.ElapsedMilliseconds.ToString())); } }
五、LinkedList集合簡介
LinkedList連結串列的底層是採用雙向連結串列的方式實現,
在連結串列(Linked List)中,每一個元素都指向下一個元素,以此來形成了一個鏈(chain)
可以從頭部和尾部插入資料,在儲存記憶體上採用非連續方式儲存,連結串列有如下一些特點
- 1、記憶體儲存上是非連續的
- 2、能夠支援從頭部和底部同時插入
- 3、長度是非固定的
優缺點:
優點:
1、由於非連續儲存,中部插入和刪除元素效率高
2、長度非固定,在建立時不用考慮其長度
3、可以衝頭部和底部新增元素
4、資料型別是安全的,在建立時需要指定的資料型別
缺點:
1、由於非連續儲存,不能通過小標訪問,查詢效率低
練習例項程式碼:
/// <summary> /// LinkedList練習操作 /// </summary> public class LinkedListTest { /// LinkedList連結串列的底層是採用雙向連結串列的方式實現, /// 在連結串列(Linked List)中,每一個元素都指向下一個元素,以此來形成了一個鏈(chain) /// 可以從頭部和尾部插入資料,在儲存記憶體上採用非連續方式儲存,連結串列有如下一些特點 /// 1、記憶體儲存上是非連續的 /// 2、能夠支援從頭部和底部同時插入 /// 3、長度是非固定的 /// 優缺點: /// 優點: /// 1、由於非連續儲存,中部插入和刪除元素效率高 /// 2、長度非固定,在建立時不用考慮其長度 /// 3、可以衝頭部和底部新增元素 /// 4、資料型別是安全的,在建立時需要指定的資料型別 /// 缺點: /// 1、由於非連續儲存,不能通過小標訪問,查詢效率低 /// LinkedList操作例項 public static void LinkedListTestOpert() { //// 定義一個秒錶,執行獲取執行時間 Stopwatch st = new Stopwatch();//例項化類 st.Start();//開始計時 //// 需要統計時間的程式碼段(統計初始化長度時的執行時間) Console.WriteLine(""); Console.WriteLine(""); Console.WriteLine("Linked集合儲存資料量為10000000,執行開始:"); LinkedList<int> list = new LinkedList<int>(); //// 定義一個數組 for (int i = 0; i < 10000000; i++) { list.AddFirst(1 + 1); } //需要統計時間的程式碼段 st.Stop();//終止計時 Console.WriteLine(string.Format("Linked集合儲存資料量為10000000,執行完畢:!總耗時{0}毫秒", st.ElapsedMilliseconds.ToString())); } }
六、沒在集合資料執行結果對比分析
class Program { static void Main(string[] args) { //// array陣列操作測試 ArrayTest.IntArrayTest(); //// arrayList集合操測試 ArrayListTest.ArrayListOpert(); //// List集合操作測試 ListTest.ListOpert(); //// LinkedList集合操作測試 LinkedListTest.LinkedListTestOpert(); ///// 通過測試資料 //通過測試資料大概可以分析得出一些結論 //1、整體效率上Array效率最高,ArrayList效率最低,List效率介於Array和ArrayList之間 //2、ArrayList和List集合,在定義時如果知道資料長度,那麼初始化時,指定長度的效率比不指定的長度效率高 //總結: //在資料集合使用選擇上給出以下一些建議: //1、Array:當元素的數量是固定的,並且需要使用下標時 //2、ArrayList:當儲存的元素型別不同時 //3、List:當元素的數量是固定的,並且需要使用下標時 //4、LinkedList:當元素需要能夠在列表的兩端新增時 Console.ReadLine(); } }
執行結果資料
通過測試資料大概可以分析得出一些結論
1、整體效率上Array效率最高,ArrayList效率最低,List效率介於Array和ArrayList之間
2、ArrayList和List集合,在定義時如果知道資料長度,那麼初始化時,指定長度的效率比不指定的長度效率高
七、總結:
在資料集合使用選擇上給出以下一些建議:
1、Array:當元素的數量是固定的,並且需要使用下標時
2、ArrayList:當儲存的元素型別不同時,初始化時給一個預估的長度
3、List:當元素的數量是固定的,並且需要使用下標時,初始化時給一個預估的長度
4、LinkedList:當元素需要能夠在列表的兩端添