[Swift]多維數組的表示和存儲:N維數組映射到一維數組(一一對應)!


★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公眾號:山青詠芝(shanqingyongzhi)
➤博客園地址:山青詠芝(https://www.cnblogs.com/strengthen/ 
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/9844577.html 
➤如果鏈接不是山青詠芝的博客園地址,則可能是爬取作者的文章。
➤原文已修改更新!強烈建議點擊原文地址閱讀!支持作者!支持原創!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

數組:有序的元素序列。 若將有限個類型相同的變量的集合命名,那么這個名稱為數組名。組成數組的各個變量稱為數組的分量,也稱為數組的元素,有時也稱為下標變量。用於區分數組的各個元素的數字編號稱為下標。數組是在程序設計中,為了處理方便, 把具有相同類型的若干元素按無序的形式組織起來的一種形式。這些無序排列的同類數據元素的集合稱為數組。數組是用於儲存多個相同類型數據的集合。

二維數組:本質上是以數組作為數組元素的數組,即“數組的數組”。二維數組又稱為矩陣,行列數相等的矩陣稱為方陣。

  對稱矩陣:a[i][j] = a[j][i]

  對角矩陣:n階方陣主對角線外都是零元素

三維數組:指維數為三的數組結構。三維數組是最常見的多維數組,由於其可以用來描述三維空間中的位置或狀態而被廣泛使用。

定義二維數組

 1 //方式1
 2 var arr1 = [[Int]]()
 3 print(arr1)
 4 //Print []
 5 
 6 //方式2
 7 var arr2 = Array<Array<Int>>()
 8 print(arr2)
 9 //Print []
10 
11 //方式3:定義3列4行的二維數組,元素初始化為0
12 var arr3 = [[Int]](repeating: [Int](repeating: 0, count: 3), count: 4)
13 print(arr3)
14 //Print [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

二維數組的遍歷

 1 //遍歷行
 2 for row in arr3 
 3 {
 4     print(row)
 5     //Print [0, 0, 0]
 6     //遍歷列
 7     for col in row
 8     {
 9         //從左到右,從上到下進行遍歷
10         print(col)
11         //Print 0
12     }
13 }

定義三維數組

 1 //方式1
 2 var arr1 = [[[Int]]]()
 3 print(arr1)
 4 //Print []
 5 
 6 //方式2
 7 var arr2 = Array<Array<Array<Int>>>()
 8 print(arr2)
 9 //Print []
10 
11 //方式3:定義三維數組,元素初始化為0,由內往外
12 var arr3 = [[[Int]]](repeating: [[Int]](repeating: [Int](repeating: 0, count: 2), count: 3), count: 4)
13 print(arr3)
14 //2個元素的一維數組,3個元素的二維數組,4個元素的三位數組
15 /*
16 [
17     [
18         [0, 0], [0, 0], [0, 0]
19     ],
20     [
21         [0, 0], [0, 0], [0, 0]
22     ],
23     [
24         [0, 0], [0, 0], [0, 0]
25     ],
26     [
27         [0, 0], [0, 0], [0, 0]
28     ]
29 ]
30 */

三維數組的遍歷

 1 //遍歷高height
 2 for height in arr3 
 3 {
 4     print(height)
 5     //Print [[0, 0], [0, 0], [0, 0]]
 6     //遍歷長depth
 7     for depth in height
 8     {
 9         print(depth)
10         //Print [0, 0]
11         //遍歷寬width
12         for width in depth
13         {
14             print(width)
15             //Print 0
16         }
17     }
18 }

使用函數來創建多維數組

1 //num:元素個數
2 //value:元素初始值
3 func dimension<T>(_ num: Int, _ value: T) -> [T] {
4   return [T](repeating: value, count: num)
5 }

示例代碼:

 1 //用嵌套的方式創建多維數組
 2 //創建一維數組
 3 let arr1 = dimension(1,0)
 4 print(arr1)
 5 //Print [0]
 6 
 7 //創建二維數組
 8 let arr2 = dimension(2,arr1)
 9 //即:let arr2 = dimension(2,dimension(1,0))
10 print(arr2)
11 //Print [[0], [0]]
12 
13 //創建三維數組
14 let arr3 = dimension(3,arr2)
15 //即:let arr3 = dimension(3,dimension(2,dimension(1,0)))
16 print(arr3)
17 //Print [[[0], [0]], [[0], [0]], [[0], [0]]]
18 
19 //創建四維數組
20 let arr4 = dimension(4,arr3)
21 //即:let arr4 = dimension(4,dimension(3,dimension(2,dimension(1,0))))
22 print(arr4)
23 //Print [[[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]]]
24 
25 //創建五維數組
26 let arr5 = dimension(5,arr4)
27 //即:arr5 = dimension(5,dimension(4,dimension(3,dimension(2,dimension(1,0)))))
28 print(arr5)
29 //Print [[[[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]]], [[[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]]], [[[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]]], [[[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]]], [[[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]], [[[0], [0]], [[0], [0]], [[0], [0]]]]]
30 
31 //......

使用函數嵌套的方法創建多維數組有一個很大的缺陷:無法明確維度所代表的意義。

所以,可以考慮使用一維數組存儲多維數組的數據。

創建一個Array2D類,用一維數組存儲二維數組的數據。

此時我們只需關注“列”和“行”的數值,細節交由Array2D來處理,這就是將原始數據類型包裝成包裝器類型或結構體的優點。

二維數組A[rows][columns]放到一維數組B中的對應公式:

兩種方式 :

(1)、按行遍歷 

A[i][j] = B[ i + j * rows ]

(2)、按列遍歷

A[i][j] = B[ i * columns + j ]

 1 public struct Array2D<T> {
 2     //列數
 3     public let columns:Int 
 4     //行數
 5     public let rows:Int 
 6     fileprivate var array: [T]
 7     
 8     //初始化
 9     public init(columns: Int, rows: Int, initialValue: T) {
10         self.columns = columns
11         self.rows = rows
12         array = .init(repeating: initialValue, count: rows*columns)
13     }
14     
15     //subscript函數可以檢索數組中的值
16     public subscript(column: Int, row: Int) -> T {
17         //讀取
18         get {
19              //先決條件
20             precondition(column <= columns, "Column \(column) Index is out of range. Array<T>(columns: \(columns), rows:\(rows))")
21             precondition(row <= rows, "Row \(row) Index is out of range. Array<T>(columns: \(columns), rows:\(rows))")
22             return array[row * columns + column]
23             //或 return array[row + column * rows]
24         }
25         //寫入
26         set {
27              //先決條件
28             precondition(column <= columns, "Column \(column) Index is out of range. Array<T>(columns: \(columns), rows:\(rows))")
29             precondition(row <= rows, "Row \(row) Index is out of range. Array<T>(columns: \(columns), rows:\(rows))")
30             array[row * columns + column] = newValue
31             //或 array[row + column * rows] = newValue
32         }
33     }
34 }

示例代碼:

 1 // 創建一個二維數組的實例
 2 var arr2D = Array2D(columns: 2, rows:3, initialValue: 0)
 3 print(arr2D)
 4 //Print Array2D<Int>(columns: 2, rows: 3, array: [0, 0, 0, 0, 0, 0])
 5 
 6 //subscript函數可以檢索數組中的元素值
 7 let num = arr2D[1, 1]
 8 print(num)
 9 //Print 0
10 
11 //給數組中的元素賦值
12 arr2D[1, 1] = 88
13 print(arr2D[1, 1])
14 //Print 88

創建一個Array3D類,用一維數組存儲三維維數組的數據。

此時我們只需關注“長”、“寬”和“高”的數值,細節交由Array3D來處理,這就是將原始數據類型包裝成包裝器類型或結構體的優點。

三維數組A[widths][depths][heights]放到一維數組B中的對應公式:
A[i][j][k] = B[ ( i - 1 ) * ( depths * heights ) + ( j - 1 ) * heights + k ]

 1 public struct Array3D<T> {
 2     //
 3     public let widths:Int
 4     //
 5     public let depths:Int
 6     //
 7     public let heights:Int
 8     fileprivate var array: [T]
 9     
10     //初始化
11     public init(widths: Int, depths: Int, heights: Int, initialValue: T) {
12         self.widths = widths
13         self.depths = depths
14         self.heights = heights
15         array = .init(repeating: initialValue, count: widths * depths * heights)
16     }
17     
18     //subscript函數可以檢索數組中的值
19     public subscript(width: Int, depth: Int, height: Int) -> T {
20         //讀取
21         get {
22             //先決條件
23             precondition(width <= widths, "Width \(width) Index is out of range. Array<T>(widths: \(widths), depths:\(depths), heights:\(heights))")
24             precondition(depth <= depths, "Depth \(depth) Index is out of range. Array<T>(widths: \(widths), depths:\(depths), heights:\(heights))")
25             precondition(height <= heights, "Height \(height) Index is out of range. Array<T>(widths: \(widths), depths:\(depths), heights:\(heights))")
26             return array[(width - 1) * (depths * heights) + (depth - 1) * heights + height]
27         }
28         //寫入
29         set {
30              //先決條件
31             precondition(width <= widths, "Width \(width) Index is out of range. Array<T>(widths: \(widths), depths:\(depths), heights:\(heights))")
32             precondition(depth <= depths, "Depth \(depth) Index is out of range. Array<T>(widths: \(widths), depths:\(depths), heights:\(heights))")
33             precondition(height <= heights, "Height \(height) Index is out of range. Array<T>(widths: \(widths), depths:\(depths), heights:\(heights))")
34             array[(width - 1) * (depths * heights) + (depth - 1) * heights + height] = newValue
35         }
36     }
37 }

示例代碼:

 1 // 創建一個三維數組的實例
 2 var arr3D = Array3D(widths: 2, depths: 3, heights: 4, initialValue: 0)
 3 print(arr3D)
 4 //Print Array3D<Int>(widths: 2, depths: 3, heights: 4, array: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
 5 
 6 //subscript函數可以檢索數組中的元素值
 7 let num = arr3D[1, 1, 1]
 8 print(num)
 9 //Print 0
10 
11 //給數組中的元素賦值
12 arr3D[1, 1, 1] = 88
13 print(arr3D[1, 1, 1])
14 //Print 88

四維維數組A[a][b][c][d]放到一維數組B中的對應公式:

A[i][j][k][w] = B[(i - 1) * (b * c * d) + (j - 1) * (c * d) + (k - 1) * d + w]

歸納演繹......

N維數組映射到一維數組

由此及彼,由表及里,歸納總結,創建一個Dim類,用一維數組存儲n維數組的數據,

此時我們只需關注每一個維度的數值,細節交由Dim來處理,這就是將原始數據類型包裝成包裝器類型或結構體的優點。

深入思考:

(1)、多維度中各維度所表示意義的順序可以任意確定,確定維度順序之后,就按照既定的維度順序進行對一維數組進行讀寫。

(2)、如同二維數組中可以按照行遍歷或者按照列遍歷一樣。多維數組也可以任意確定多維數組中下標i、j、k、w、...的順序。

下標順序確定之后就不可變更,根據下標順序得出對應公式,公式從上文中請歸納,就按照既定的下標順序進行對一維數組進行讀寫。

 1 public struct Dim<T> {
 2     //用一個數組來接收維度信息
 3     //元素個數為維度
 4     //元素數值為對應維度的具體數量
 5     public let dimension:[Int]
 6     fileprivate var array:[T]
 7     //只能初始化一次
 8     public let product:Int
 9     //數組信息
10     public let arrayInfo:String
11     
12     //初始化
13     public init(dimension:[Int], initialValue: T) {
14         self.dimension = dimension
15         //數組各元素求積reduce(1)
16         //用於一維數組保存多維數組的信息
17         self.product = dimension.reduce(1) {$0 * $1}
18         //初始化數組
19         array = .init(repeating: initialValue, count: product)
20         //初始化維度信息
21         var str:String = " Array<T>("
22         for i in 0...(dimension.count - 1)
23         {
24            str += String(i + 1) + "Dimension: \(dimension[i])," 
25         }
26         //刪除最后一個字符串‘,’
27         str.remove(at: str.index(before: str.endIndex))
28         str += ")"
29         arrayInfo = str
30     }
31     
32     //subscript函數可以檢索數組中的值
33     //T?:讀取時如果輸入的維度不等於原維度則返回nil
34     //取值需使用強制解包
35     public subscript(_ numbers: Int...) -> T? {
36         //讀取
37         get 
38         {
39             //判斷元素個數是否等於維度數組個數
40             if numbers.count == dimension.count
41             {
42                 for i in 0...(dimension.count - 1)
43                 {
44                     //先決條件
45                     precondition( numbers[i] <= dimension[i], "\(String(i + 1))Dimension:\(numbers[i]) Index is out of range. " + arrayInfo)
46                 }
47                 return array[getIndex(numbers)]
48             }
49             return nil
50         }
51         
52         //寫入
53         set 
54         {
55             //判斷元素個數是否等於維度數組個數
56             if numbers.count == dimension.count
57             {
58                 for i in 0...(dimension.count - 1)
59                 {
60                     //先決條件
61                     precondition( numbers[i] <= dimension[i], "\(String(i + 1))Dimension:\(numbers[i]) Index is out of range. " + arrayInfo)
62                 }                
63                 array[getIndex(numbers)] = newValue!
64             }
65         }
66         
67     }
68     //求解多維數組的元素在一維數組中的索引
69     private func getIndex(_ dim: [Int]) -> Int
70     {
71         var sum:Int = 0
72         for index in 0...(dim.count - 1)
73         {
74            sum += (dim[index] - 1) * getProduct(index)
75         }
76         return sum 
77     }
78     //求部分元素的積
79     private func getProduct(_ index:Int) -> Int
80     {
81         //數組各元素求積
82         var accumulate:Int = 1
83         //加1
84         var front:Int = index + 1
85         let real:Int = dimension.count - 1
86         if real > front
87         {
88             let arr:[Int] = [Int](dimension[front...real])
89             if arr.count != 0
90             {
91                 //數組各元素求積reduce(1)
92                 accumulate = arr.reduce(1){$0 * $1}
93             }
94         }
95         return accumulate
96     }
97 }

Dim類,用一維數組存儲n維數組的數據,示例:

 1 // 創建一維數組的實例
 2 var arr1 = Dim(dimension:[3], initialValue: 1)
 3 print(arr1)
 4 //Print Dim<Int>(dimension: [3], array: [1, 1, 1], product: 3, arrayInfo: " Array<T>(1Dimension: 3)")
 5 // 創建二維數組的實例
 6 var arr2 = Dim(dimension:[1,2], initialValue: 2)
 7 print(arr2)
 8 //Print Dim<Int>(dimension: [1, 2], array: [2, 2], product: 2, arrayInfo: " Array<T>(1Dimension: 1,2Dimension: 2)")
 9 // 創建三維數組的實例
10 var arr3 = Dim(dimension:[1,2,3], initialValue: 3)
11 print(arr3)
12 //Print Dim<Int>(dimension: [1, 2, 3], array: [3, 3, 3, 3, 3, 3], product: 6, arrayInfo: " Array<T>(1Dimension: 1,2Dimension: 2,3Dimension: 3)")
13 // 創建四維數組的實例
14 var arr4 = Dim(dimension:[1,2,3,4], initialValue: 4)
15 print(arr4)
16 //Print Dim<Int>(dimension: [1, 2, 3, 4], array: [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], product: 24, arrayInfo: " Array<T>(1Dimension: 1,2Dimension: 2,3Dimension: 3,4Dimension: 4)")
17 // 創建五維數組的實例
18 var arr5 = Dim(dimension:[1,2,3,4,5], initialValue: 5)
19 print(arr5)
20 //Print Dim<Int>(dimension: [1, 2, 3, 4, 5], array: [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], product: 120, arrayInfo: " Array<T>(1Dimension: 1,2Dimension: 2,3Dimension: 3,4Dimension: 4,5Dimension: 5)")
21 //......
22 
23 //subscript函數可以檢索數組中的元素值,Optional為可選類型
24 //一維數組
25 arr1[2] = 11
26 print(arr1)
27 //Print Dim<Int>(dimension: [3], array: [1, 11, 1], product: 3, arrayInfo: " Array<T>(1Dimension: 3)")
28 let num1 = arr1[1]
29 print(num1)
30 //Print Optional(1)
31 //二維數組
32 arr2[1,2] = 22
33 print(arr2)
34 //Print  Dim<Int>(dimension: [1, 2], array: [2, 22], product: 2, arrayInfo: " Array<T>(1Dimension: 1,2Dimension: 2)")
35 let num2 = arr2[1,1]
36 print(num2)
37 //Print Optional(22)
38 //三維數組
39 arr3[1,1,1] = 33
40 print(arr3)
41 //Print Dim<Int>(dimension: [1, 2, 3], array: [33, 3, 3, 3, 3, 3], product: 6, arrayInfo: " Array<T>(1Dimension: 1,2Dimension: 2,3Dimension: 3)")
42 let num3 = arr3[1,1,1]
43 print(num3)
44 //Print Optional(33)
45 //四維數組
46 arr4[1,1,1,1] = 44
47 print(arr4)
48 //Print Dim<Int>(dimension: [1, 2, 3, 4], array: [44, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], product: 24, arrayInfo: " Array<T>(1Dimension: 1,2Dimension: 2,3Dimension: 3,4Dimension: 4)")
49 let num4 = arr4[1,1,1,1]
50 print(num4)
51 //Print Optional(44)
52 //五維數組
53 arr5[1,1,1,1,1] = 55
54 print(arr5)
55 //Print Dim<Int>(dimension: [1, 2, 3, 4, 5], array: [55, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], product: 120, arrayInfo: " Array<T>(1Dimension: 1,2Dimension: 2,3Dimension: 3,4Dimension: 4,5Dimension: 5)")
56 let num5 = arr5[1,1,1,1,1]
57 print(num5)
58 //Print Optional(55)
59 //......

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM