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 //......
  • 相关阅读:
    Count and Say leetcode
    Find Minimum in Rotated Sorted Array II leetcode
    Find Minimum in Rotated Sorted Array leetcode
    Search in Rotated Sorted Array II leetcode
    search in rotated sorted array leetcode
    Substring with Concatenation of All Words
    Subsets 子集系列问题 leetcode
    Sudoku Solver Backtracking
    Valid Sudoku leetcode
    《如何求解问题》-现代启发式方法
  • 原文地址:https://www.cnblogs.com/strengthen/p/9844577.html
Copyright © 2011-2022 走看看