zoukankan      html  css  js  c++  java
  • [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( 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 //......
  • 相关阅读:
    第十篇 .NET高级技术之委托
    第九篇 .NET高级技术ref、out
    文华财经函数大全
    为字段创建全文检索索引
    C#.NET中代码注释提示
    WPF中的资源引用心得
    XAML文件动态加载
    spring MVC找不到JS的问题
    Oracle性能监控脚本
    ExtJs之Ext.data.Store
  • 原文地址:https://www.cnblogs.com/strengthen/p/9844577.html
Copyright © 2011-2022 走看看