# 資料結構 ## 陣列 ### 一維陣列 ``` csharp var arr = new int[3] { 1, 2, 3 }; ``` [Example](https://dotnetfiddle.net/8RV5Pq) ### 二維陣列 二維陣列的定義是把第一維度的長度放在最後一個,並且把第二維度的長度放在前面 ![](https://i.imgur.com/2KEEblz.png) ``` csharp var arr = new int[4, 7] { {1, 2, 3, 4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14}, {15, 16, 17, 18, 19, 20, 21}, {22, 23, 24, 25, 26, 27, 28} }; for (int i = 0; i < arr.GetLength(0); i++) { for (int j = 0; j < arr.GetLength(1); j++) { Console.Write(arr[i,j]); } Console.WriteLine(); } ``` [Example](https://dotnetfiddle.net/79I0Pc) ### 多維陣列 三維以上即為多維陣列。 三維陣列的定義是把第一維度的長度放在最後一個,並且把第二維度的長度放在第二個,第三維度放在第一個; 以此類推,因此維度跟定一時的順是反過來的 ``` 維度: 3 2 1 var arr = new int[3,3,3] 維度: 4 3 2 1 var arr = new int[4,3,2,1] 維度: 5 4 3 2 1 var arr = new int[3,2,3,1,2] ``` ``` csharp var arr = new int[2, 3, 4, 7] { { { {1, 2, 3, 4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14}, {15, 16, 17, 18, 19, 20, 21}, {22, 23, 24, 25, 26, 27, 28} }, { {1, 2, 3, 4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14}, {15, 16, 17, 18, 19, 20, 21}, {22, 23, 24, 25, 26, 27, 28} }, { {1, 2, 3, 4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14}, {15, 16, 17, 18, 19, 20, 21}, {22, 23, 24, 25, 26, 27, 28} } }, { { {1, 2, 3, 4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14}, {15, 16, 17, 18, 19, 20, 21}, {22, 23, 24, 25, 26, 27, 28} }, { {1, 2, 3, 4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14}, {15, 16, 17, 18, 19, 20, 21}, {22, 23, 24, 25, 26, 27, 28} }, { {1, 2, 3, 4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14}, {15, 16, 17, 18, 19, 20, 21}, {22, 23, 24, 25, 26, 27, 28} } } }; for (int i = 0; i < arr.GetLength(0); i++) { Console.WriteLine("四維:"); for (int j = 0; j < arr.GetLength(1); j++) { Console.WriteLine(" 三維:"); for (int k = 0; k < arr.GetLength(2); k++) { Console.WriteLine(" 二維:"); for (int l = 0; l < arr.GetLength(3); l++) { Console.Write(" 一維:"+arr[i, j, k, l]+", "); } Console.WriteLine(); } Console.WriteLine(); } Console.WriteLine(); } ``` [Example](https://dotnetfiddle.net/gHgUgN) ## 連結串列 ### 單向連結串列 每一個節點都會包含**指標**跟**值**,必須透過讀取指標依照順序一路下去才能找到下一個**值**的所在位址,無法回頭往前推。 ![](https://i.imgur.com/W85vfuC.png) ### 雙向連結串列 每一個節點都會包含 **2個指標** 跟 **1個值** ,可以透過 **往前** 或 **往後** 的來找到 **前一個** 或 **後一個** **值** 的所在位址。每次增加節點會需要調整4個指標,刪除會調整2個指標 ![](https://i.imgur.com/DgvHvOX.png) ### 環狀連結串列 每一個節點都會包含 **1個指標** 跟 **1個值** ,是單向連結串列的頭尾會相連。 ![](https://i.imgur.com/xVYG1GM.png) ## 堆疊 屬於後進先出的資料結構(LIFO,Last In First Out),後進的資料會被提早取到; 一般可以用陣列去實作,但 C# 有內建 Stack ![](https://i.imgur.com/vSbY3LB.png) ``` csharp var numbers = new Stack<string>(); numbers.Push("1"); numbers.Push("2"); numbers.Push("3"); numbers.Push("4"); numbers.Push("5"); foreach( string number in numbers ) //依序印出 { Console.WriteLine(number); } Console.WriteLine("\n取出最頂端的資料 : " + numbers.Pop()); Console.WriteLine("\n取出最頂端的資料 : " + numbers.Pop()); Console.WriteLine("\n取出最頂端的資料 : " + numbers.Pop()); Console.WriteLine("\n取出最頂端的資料 : " + numbers.Pop()); Console.WriteLine("\n取出最頂端的資料 : " + numbers.Pop()); ``` [Example](https://dotnetfiddle.net/m44M09) ## 佇列 先進先出(FIFO,First In First Out),資料的概念必須以下幾個特點: 1. 有 2 個端點,分為 **前端** 及 **後端**; 2. 後端只可以 **新增** 資料 3. 前端只能 **刪除** 及 **修改** 資料 4. 資料的存取必須符合先進先出的概念 ![](https://i.imgur.com/NnX7VKF.png) C#有內建 Queue 實現這個資料 ``` csharp var numbers = new Queue<string>(); numbers.Enqueue("1"); //將資料加入的後端 numbers.Enqueue("2"); numbers.Enqueue("3"); numbers.Enqueue("4"); numbers.Enqueue("5"); foreach( string number in numbers ) { Console.WriteLine(number); } //從的前端頭移除最早加入的元素 Console.WriteLine("\n取出前端的資料 : "+ numbers.Dequeue()); Console.WriteLine("\n取出前端的資料 : "+ numbers.Dequeue()); Console.WriteLine("\n取出前端的資料 : "+ numbers.Dequeue()); Console.WriteLine("\n取出前端的資料 : "+ numbers.Dequeue()); Console.WriteLine("\n取出前端的資料 : "+ numbers.Dequeue()); ``` [Example](https://dotnetfiddle.net/5WvmZS) ## 樹 Tree 樹狀結構是一種階層式的架構,只有上對下或下對上的關係,不會有前後的關係,不可為空集合。 1. 由一個或多個節點組成的集合,會有一個根節點,放在最頂層,接著再沿著分支逐漸往下延伸; 2. 每個節點只會跟上下層的節點透過分支有連結 3. 不會有迴路存在 ![](https://i.imgur.com/lkFcVDk.png) **一些名詞解釋:** * 根節點:最頂端的節點,不會有父節點,只會有子節點;如圖上的 Alice * 父節點:如果該節點下面有節點,即為父節點;如圖上的 Alice, Bob, Chris * 子節點:如果該節點上面有節點,即為子節點;如圖上除了的 Alice 之外的節點全部都是子節點 * 兄弟節點:如果有共同的父節點,且為同一層,即為兄弟節點;如圖上的 Bob, Chris, David 為兄弟節點,Eva, Frank 也是兄弟節點 * 分支度:父節點的下一層有幾個子節點;如圖上的 Alice 的分支度是 3 因為有 3 個子節點, Bob 的分支度為2 因為有 2 個子節點 * 終端節點或樹葉:沒有任何子節點;如圖上的 Eva, Frank, Gina * 非終端節點:沒有任何子節點;如圖上的 Eva, Frank, Gina 意外的均為非終端節點 * 階層:位於樹狀結構的第幾層;如圖上的 Alice 在第一層,Frank 在第三層 * 高度:總共有幾層節點;如圖上總共有3層 ### 二元樹 Binary Tree 每一節點的子節點只會有0~2個,分別為 **左子樹 ** 及 **右子樹 **;有 **次序** 關係,**先左後右**;可以為空集合 **樹及二元樹之比較:** |樹 tree|二元樹 binary tree| |:----:|:----:| |不可以為空|可以為空(空集合)| |Node's degree $\geq$ 0即可|0 $\leq$ Node's degree $\leq$ 2| |子樹之間無次序/方向之分|子樹有左右之分| ![](https://i.imgur.com/TsP5gIM.png) **完滿二元樹(Full B.T.,Full Binary Tree)** 代表一個樹在特定高度 **i** 下,所能出現的節點數量有符合以下公式的樹,即為完滿二元樹,此公式也代表一個樹的最大值: 公式:==$2^{i-1}$== ex. 下圖的樹就是完滿二元樹,i為3 :::info $2^{3}-1$ => $8-1$ => $7$ ::: ![](https://i.imgur.com/aPhSC7A.png) 推演過程: ![](https://i.imgur.com/L4a9u4Q.png) **完整二元樹(Complete B.T.,Complete Binary Tree)** 需符合以下 2 個條件: 1. 節點數量除了最後一層之外,皆有完整填滿,公式:2^i-1^-1 < N < 2^i^-1 :::info 當 i = 3,則數量為 3~6 ==> 2^3-1^-1 < n < 2^3-1 ==> 2^2^-1 < n < 2^3^-1 ==> 4-1 < n < 8-1 ==> 3 < n < 7 ::: 2. 需照順序排序,由上到下,由左到右,如果不照順序即不為完整二元樹 以上圖來說,圖節點數量在下圖紅框處內即為完整二元樹 ![](https://i.imgur.com/AsGUn2r.png) ![](https://i.imgur.com/hsyix7M.png) ### 歪斜樹 Skewed Binary Tree 節點只有左子樹或右子樹時,即為歪斜樹 ![](https://i.imgur.com/5lEFgf6.png) ### 嚴格二元樹 Strict Binary Tree 所有的非葉子節點的分支度都是2,即為嚴格二元樹 ![](https://i.imgur.com/qE7rhGS.png) ### 二元樹的程式表示 二元樹可以用陣列或連結串列來表示 |陣列|連結串列| |:----:|:----:| |訪問快|搜尋效率低| |插入和刪除效率低|插入刪除效率高| #### 陣列 1. 通常 Index 0 都會留空,從 Index 1 開始存放,Index 1 為根節點 2. 節點依照順序存放,從上到下,從左到右 ![](https://i.imgur.com/PB2ovH1.png) 公式: i 為索引,計算後的值(四捨五入)代表該節點的索引 * 父節點: (i-1)/2 * 左子樹: 2 x i * 右子樹: 2 x i - 1 ex. C 的索引是 3,故 C 的父節點是 (2-1)/2=1,因此 C 的父節點存在 Index 1 的位置 C 的索引是 3,故 C 的左子樹是 2x3=6,因此 C 的左子樹存在 Index 6 的位置 C 的索引是 3,故 C 的右子樹是 2x3+1=6,因此 C 的右子樹存在 Index 7 的位置 ![](https://i.imgur.com/Sg2yGrS.png) :::info 使用陣列儲存歪斜樹,如下圖,Index 2, 4, 5, 6 的記憶體全部都被浪費了 故陣列只適合儲存完滿二元樹或完整二元樹,且增加或搬移節點時,需要搬移多個節點 ![](https://i.imgur.com/J1iVRMF.png) ![](https://i.imgur.com/AEDK2qR.png) ::: #### 連結串列 1. 節點容易新增或刪除 2. 不容易找父節點 因為雙向連結串列剛好是1個值加上2個指標,因此剛好可以用來表示二元樹,用連結串列來表示二元樹比較節省空間,但在樹葉仍然會有一些指標的浪費 如下圖: **完整二元樹:** ![](https://i.imgur.com/a5ybLor.png) **右歪斜樹:** ![](https://i.imgur.com/ZaHoPL8.png) 通常程式碼結構會如下: ``` C struct Node{ Node* Lchild; Node* Rchild; int data; }; ``` ### 二元樹排序走訪 Binary Tree Traversal #### 中序走訪 ###### tags: `資料結構`