1. 程式人生 > 其它 >c# 開發中最常用的幾種資料結構

c# 開發中最常用的幾種資料結構

說明:以下程式基於 vs2019  .Net Framework4.7.2 下進行測試。

 

一、記憶體上連續儲存,節約空間,可以索引訪問,讀取快,增刪慢

 

1.Array  陣列,是記憶體上連續分配的一組資料物件

優點:可以根據下標讀取和寫入,讀取速度快

缺點:寫入較慢,固定長度,只能儲存一種基礎資料型別

//Array:在記憶體上連續分配的,而且元素型別是一樣的
            //可以座標訪問  讀取快--增刪慢,長度不變
            Console.WriteLine("***************Array******************");
            
int[] intArray = new int[3]; intArray[0] = 1; intArray[0] = 12; intArray[0] = 123; string[] strArray = new string[] { "1", "2" };//Array

 

2.ArrayList  陣列,是記憶體上連續分配的一組資料物件

優點:不固定長度,可以根據資料自動改變大小,可以根據下標讀取和寫入,讀取速度快

缺點:所有資料型別都會當作object型別處理,有裝箱和拆箱操作,效能較慢,,不是型別安全的

 //ArrayList  不定長的,連續分配的;
            //元素沒有型別限制,任何元素都是當成object處理,如果是值型別,會有裝箱操作
            //讀取快--增刪慢
            Console.WriteLine("***************ArrayList******************");
            System.Collections.ArrayList arrayList = new System.Collections.ArrayList();
            arrayList.Add(true);
            arrayList.Add(
"a"); arrayList.Add(32);//add增加長度 //arrayList[4] = 26;//索引複製,不會增加長度 //刪除資料 //arrayList.RemoveAt(4); var value = arrayList[2]; arrayList.RemoveAt(0); arrayList.Remove(true);

3.List  陣列,是記憶體上連續分配的一組資料物件

優點:不固定長度,可以根據資料自動改變大小,讀取速度快

缺點:只能儲存一種基礎資料型別,增刪較慢,,是型別安全的

//List:也是Array,記憶體上都是連續擺放;不定長;泛型,保證型別安全,避免裝箱拆箱
            //讀取快--增刪慢
            Console.WriteLine("***************List<T>******************");
            List<int> intList = new List<int>() {};
            intList.Add(1);
            intList.Add(2);
            intList.Add(3);
            foreach(var i in intList)
            {
                Console.WriteLine(i.ToString());
            }

 

二、非連續擺放,儲存資料+地址,找資料的話就只能順序查詢,讀取慢;增刪快

1.LinkedLis  泛型連結串列,是記憶體上不連續分配的一組資料物件

優點:節點值可以重複,增刪改資料時,不需要移動前後資料位置,效能較快,是型別安全的

缺點:不能通過下標訪問,查詢資料只能按照順序查詢,查詢較慢,只能儲存一種基礎資料型別

 //LinkedList:泛型的特點;連結串列,元素不連續分配,每個元素都有記錄前後節點
            //節點值可以重複
            //能不能下標訪問?不能,找元素就只能遍歷  查詢不方便
            //增刪 就比較方便
            Console.WriteLine("***************LinkedList<T>******************");
            LinkedList<int> linkedList = new LinkedList<int>();
            //linkedList[3]
            linkedList.AddFirst(1);//新增為第一個節點元素
            linkedList.AddFirst(1);//新增為第一個節點元素
            linkedList.AddLast(3);//新增為最後一個節點元素

            bool isContain = linkedList.Contains(1);
            LinkedListNode<int> node1 = linkedList.Find(1);  //元素123的位置  從頭查詢
            linkedList.AddBefore(node1, 0);//節點不存在,會報錯
            linkedList.AddBefore(node1, 0);//在指定節點前新增元素
            linkedList.AddAfter(node1, 2);//在指定節點後新增元素

            linkedList.Remove(3);//刪除指定值,不存在會報錯
            linkedList.Remove(node1);//刪除指定節點
            linkedList.RemoveFirst();//刪除第一個元素
            linkedList.RemoveLast();//刪除最後一個元素
            linkedList.Clear();

 

2.Queue 佇列,其實也是一種特殊連結串列,資料是先進先出(我們可以想象一下把資料放進水管裡面)

適用場景:業務模組解耦,提高系統負載,系統併發的處理能力。

//Queue 就是連結串列  先進先出  放任務延遲執行,A不斷寫入日誌任務  B不斷獲取任務去執行
            Console.WriteLine("***************Queue<T>******************");
            Queue<string> numbers = new Queue<string>();
            numbers.Enqueue("1");//新增物件到佇列末尾
            numbers.Enqueue("2");
            numbers.Enqueue("3");
            numbers.Enqueue("4");
            numbers.Enqueue("5");
            numbers.Enqueue("6");

            foreach (string number in numbers)
            {
                Console.WriteLine(number);
            }

            Console.WriteLine($"Dequeuing '{numbers.Dequeue()}'");//Dequeue方法 移除並返回佇列的第一個元素
            Console.WriteLine($"Peek at next item to dequeue: { numbers.Peek()}");//Peek方法 返回佇列的第一個元素 但不移除元素
            Console.WriteLine($"Dequeuing '{numbers.Dequeue()}'");

            Queue<string> queueCopy = new Queue<string>(numbers.ToArray());
            foreach (string number in queueCopy)
            {
                Console.WriteLine(number);
            }

            Console.WriteLine($"queueCopy.Contains(\"4\") = {queueCopy.Contains("4")}");
            queueCopy.Clear();
            Console.WriteLine($"queueCopy.Count = {queueCopy.Count}");

 

2.Stack 棧,其實也是一種特殊連結串列,和佇列不一樣的是資料是先進後出(我們可以想象一下把資料放進瓶子裡面)

適用場景:需要進行先進後出的資料處理時。

//佇列是水管,棧是有瓶底的瓶子
            {
                //Stack 就是連結串列  先進後出  解析表示式目錄樹的時候,先產生的資料後使用
                //操作記錄為命令,撤銷的時候是倒序的
                Console.WriteLine("***************Stack<T>******************");
                Stack<string> numbersStack = new Stack<string>();
                numbersStack.Push("1");
                numbersStack.Push("2");
                numbersStack.Push("3");
                numbersStack.Push("4");
                numbersStack.Push("5");//放進去

                foreach (string number in numbersStack)
                {
                    Console.WriteLine(number);
                }

                Console.WriteLine($"Pop '{numbersStack.Pop()}'");//獲取並移除
                Console.WriteLine($"Peek at next item to dequeue: { numbersStack.Peek()}");//獲取不移除
                Console.WriteLine($"Pop '{numbersStack.Pop()}'");

                Stack<string> stackCopy = new Stack<string>(numbersStack.ToArray());
                foreach (string number in stackCopy)
                {
                    Console.WriteLine(number);
                }

                Console.WriteLine($"stackCopy.Contains(\"4\") = {stackCopy.Contains("4")}");
                stackCopy.Clear();
                Console.WriteLine($"stackCopy.Count = {stackCopy.Count}");
            }

 

三、Set 純粹的集合,容器,唯一性

1.hashset 元素之間沒有關聯,hash分佈,自動增加容量大小,自動去重

使用場景:統計投票明細,關注列表/粉絲集合等

//集合:hash分佈,元素間沒關係,動態增加容量  去重
            //統計使用者IP;IP投票   交叉並補--二次好友/間接關注/粉絲合集
            Console.WriteLine("***************HashSet<string>******************");
            HashSet<string> hashSet = new HashSet<string>();
            hashSet.Add("1");
            hashSet.Add("2");
            hashSet.Add("3");
            hashSet.Add("4");
            hashSet.Add("5");
            hashSet.Add("5");
            //hashSet[0];
            foreach (var item in hashSet)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine(hashSet.Count);
            Console.WriteLine(hashSet.Contains("12345"));

            {
                HashSet<string> hashSet1 = new HashSet<string>();
                hashSet1.Add("123");
                hashSet1.Add("689");
                hashSet1.Add("789");
                hashSet1.Add("12435");
                hashSet1.Add("12435");
                hashSet1.Add("12435");
                hashSet1.SymmetricExceptWith(hashSet);//
                hashSet1.UnionWith(hashSet);//
                hashSet1.ExceptWith(hashSet);//
                hashSet1.IntersectWith(hashSet);//// 找出共同的好友
            }
            hashSet.ToList();
            hashSet.Clear();

 

2.SortedSet 排序的集合,自動去重,而且是有序的

使用場景:統計排名--每統計一個就丟進去集合,各類排行榜

 //排序的集合:去重  而且排序  
            //統計排名--每統計一個就丟進去集合
            Console.WriteLine("***************SortedSet<string>******************");
            SortedSet<string> sortedSet = new SortedSet<string>();
            //IComparer<T> comparer  自定義物件要排序,就用這個指定
            sortedSet.Add("1");
            sortedSet.Add("2");
            sortedSet.Add("3");
            sortedSet.Add("4");
            sortedSet.Add("5");
            sortedSet.Add("5");

            foreach (var item in sortedSet)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine(sortedSet.Count);
            Console.WriteLine(sortedSet.Contains("12345"));
            {
                SortedSet<string> sortedSet1 = new SortedSet<string>();
                sortedSet1.Add("123");
                sortedSet1.Add("689");
                sortedSet1.Add("456");
                sortedSet1.Add("12435");
                sortedSet1.Add("12435");
                sortedSet1.Add("12435");
                sortedSet1.SymmetricExceptWith(sortedSet);//
                sortedSet1.UnionWith(sortedSet);//
                sortedSet1.ExceptWith(sortedSet);//
                sortedSet1.IntersectWith(sortedSet);//
            }

            sortedSet.ToList();
            sortedSet.Clear();

 

四、有沒有讀取&增刪都比較快的資料型別呢? 哎,還真有有,我們來看看這個 hash雜湊 字典

key-value結構儲存,動態擴充大小,一段連續有限空間儲存(hash是用空間換效能),根據key的雜湊值計算得到儲存值的的索引,這樣查詢,增刪改都比較快。不像陣列那樣需要移動相鄰元素

所以效率比較高,基於key計算雜湊值,可能會出現重複情況(第二個雜湊值自動在前面+1),資料量大的話,效能會下降。

1.HashTable

優點:查詢,增刪改比較快,

缺點:儲存的key和value都是 object 型別,有裝箱和拆箱操作,影響效能。

 //Hashtable key-value  體積可以動態增加 拿著key計算一個地址,然後放入key - value
            //object-裝箱拆箱  如果不同的key得到相同的地址,第二個在前面地址上 + 1
            //查詢的時候,如果地址對應資料的key不對,那就 + 1查詢。。
            //浪費了空間,Hashtable是基於陣列實現
            //查找個資料  一次定位; 增刪 一次定位;  增刪查改 都很快
            //浪費空間,資料太多,重複定位定位,效率就下去了
            Console.WriteLine("***************Hashtable******************");
            System.Collections.Hashtable table = new System.Collections.Hashtable();
            table.Add("1", "1111111111111111");
            table[234] = 234;
            table[567] = 567;
            table["eleven"] = 456;
            foreach (System.Collections.DictionaryEntry objDE in table)
            {
                Console.WriteLine(objDE.Key.ToString());
                Console.WriteLine(objDE.Value.ToString());
            }
            //執行緒安全
            System.Collections.Hashtable.Synchronized(table);//只有一個執行緒寫  多個執行緒讀

 

2.Dictionary字典:泛型;key - value,增刪查改 都很快;有序的

 //字典:泛型;key - value,增刪查改 都很快;有序的
            //  字典不是執行緒安全 ConcurrentDictionary
            Console.WriteLine("***************Dictionary******************");
            Dictionary<int, string> dic = new Dictionary<int, string>();
            dic.Add(1, "HaHa");
            dic.Add(5, "HoHo");
            dic.Add(3, "HeHe");
            dic.Add(2, "HiHi");
            dic.Add(4, "HuHu1");
            dic[4] = "HuHu";//相同key替換原值
            dic.Add(4, "HuHu");//相同key,會報錯
            foreach (var item in dic)
            {
                Console.WriteLine($"Key:{item.Key}, Value:{item.Value}");
            }

3.SortedDictionary 排序字典

Console.WriteLine("***************SortedDictionary******************");
            SortedDictionary<int, string> dicS = new SortedDictionary<int, string>();
            dicS.Add(1, "HaHa");
            dicS.Add(5, "HoHo");
            dicS.Add(3, "HeHe");
            dicS.Add(2, "HiHi");
            dicS.Add(4, "HuHu1");
            dicS[4] = "HuHu";//相同key替換原值
            dicS.Add(4, "HuHu");//相同key,會報錯
            foreach (var item in dicS)
            {
                Console.WriteLine($"Key:{item.Key}, Value:{item.Value}");
            }

4.SortedList 排序集合

  Console.WriteLine("***************SortedList******************");
            System.Collections.SortedList sortedList = new System.Collections.SortedList();//IComparer
            sortedList.Add("First", "Hello");
            sortedList.Add("Second", "World");
            sortedList.Add("Third", "!");

            sortedList["Third"] = "~~";//相同key替換原值
            sortedList.Add("Fourth", "!");
            sortedList.Add("Fourth", "!");//重複的Key Add會錯
            sortedList["Fourth"] = "!!!";
            var keyList = sortedList.GetKeyList();
            var valueList = sortedList.GetValueList();

            sortedList.TrimToSize();//用於最小化集合的記憶體開銷

            sortedList.Remove("Third");
            sortedList.RemoveAt(0);
            sortedList.Clear();

 

五、執行緒安全的幾種資料結構

//ConcurrentQueue 執行緒安全版本的Queue
//ConcurrentStack 執行緒安全版本的Stack
//ConcurrentBag 執行緒安全的物件集合
//ConcurrentDictionary 執行緒安全的Dictionary
//BlockingCollection