Array ADT

一维数组是连续元素的集合,其中的每个元素都可以通过唯一的整数下标来存取。数组的大小在创建后不能修改。

ADT 定义:

  • Array(size): 创建一个长度为 size 的一维数组,并且将每个元素初始化成 None
  • length(): 返回数组中的元素个数
  • getitem(index): 返回指定下标的元素
  • setitem(index, value): 修改数组中 index 位置的元素值
  • clearing(value): 将数组中的所有元素值重置成 value
  • iterator(): 返回迭代器

Array 的实现

ctypes 模块

Python 中的许多数据类型及类实际上都是基于低层 C 语言中的相关类型实现的。Python 标准库中的 ctypes 模块可用来访问 C 语言中的各种类型及 C 类库中的功能。使用 ctypes 提供的大多数功能都要求理解一些 C 语言知识。

类似 Python 实现 string, list, tuple 和 dict,我们通过 ctypes 创建一个数组,其中的元素都是 Python 对象引用:

for i in range(5):slots[i] = None

这个数组必须先初始化后才能访问,不然会抛出异常,如 slots[0] 会抛出异常,初始化如下:

import ctypesclass Array:def __init__( self, size ):assert size > 0, "Array size must be > 0"self._size = sizePyArrayType = ctypes.py_object * sizeself._elements = PyArrayType()self.clear( None )def __len__( self ):return self._sizedef __getitem__( self, index ):assert index >= 0 and index < len(self), "Array subscript out of range"return self._elements[ index ]def __setitem__( self, index, val ):assert index >= 0 and index < len(self), "Array subscript out of range"self._elements[ index ] = valdef clear( self, val ):for i in xrange( self._size ):self._elements[ i ] = valdef __iter__( self ):return _ArrayGenerator( self._elements, self._size )def _ArrayGenerator( elements, size ):for i in range( size ):yield elements[i]

Array 的实现如下:

pyList = [4, 12, 2, 34, 17]

Python List

Python List 也是通过低层的 C 语言类型实现的,它是一个可修改的序列容器,其大小可以随着元素的添加和删除自动改变。

创建一个 Python List

pyListA = [34, 12]
pyListB = [4, 6, 31, 9]
pyListA.extend(pyListB)

以上代码将调用 list() 构造器,构造器将创建一个数组结构用来存储列表中的元素。实际上初始创建的数组大小会大于所需的容量,这样便于以后的扩展操作。

用于存储列表元素的数组实际上是刚才创建的数组中的一个子数组 subarraylen(lst) 返回该子数组的长度,而整个数组的长度为 capacity。 用数组实现的 Python List 的抽象和物理视图如下:

追加元素 append

当数组容量足够时,新元素将追加到数组中,并且 list 的 length 域也相应增加。

当数组満时,List 会进行自动扩展,即:

  1. 新建一个更大容量的数组
  2. 将原数组的元素全部复制到新建的数组
  3. 将新建的数组设置为 List 的数据结构
  4. 销毁旧的数组

新建数组的大小是根据原数组的大小确定的,比如说,新数组的大小定为原数组大小的 2 倍 。 扩展后再在数组后追加元素。

扩充列表 extend

比如:

pyList.insert(3, 79)

当 pyListA 中的数组容量不够时,List 会自动进行如 append 进行的类似数组扩展操作。

插入 insert

比如:

pyList.pop(0) # remove the first item
pyList.pop() # remove the last item

当位置 3 已经有元素时,位置 3 及其后面的所有元素都将后移一个位置,并在位置 3 插入新元素。当数组容器不够,会进行和上面相似的数组扩展操作。

删除 pop

比如:

class Array2D:def __init__( self, nrows, ncols ):# Create a 1-D array to store an array reference for each row.self._theRows = Array( nrows )# Create the 1-D arrays for each row of the 2-D array.for i in range( nrows ):self._theRows[i] = Array( ncols )def numRows( self ):return len( self._theRows )def numCols( self ):return len( self._theRows[0] )# Clears the array by setting every element to the given value.def clear( self, val ):for row in range( self.numRows() ):self._theRows[row].clear( val )def __getitem__( self, xy ):assert len( xy ) == 2, "Invalid number of array subscripts."row = xy[0]col = xy[1]assert row >= 0 and row < self.numRows() and \col >= 0 and col < self.numCols(), "Array subscript out of range."the1arr = self._theRows[row]return the1arr[col]def __setitem__( self, xy, val ):assert len( xy ) == 2, "Invalid number of array subscripts."row = xy[0]col = xy[1]assert row >= 0 and row < self.numRows() and \col >= 0 and col < self.numCols(), "Array subscript out of range."the1arr = self._theRows[row]the1arr[col] = val

删除后,如果后面还有元素,那么被删除元素后面的所有元素将前移一个位置,以便填充删除后的空位。

当然,如果删除后的数组空位过多,也会进行相对应的收缩数组操作。

List Slice

Slice 会创建一个新的 List。

二维数组 two-dimensional array

它将数据组织成行和列,类似于表格。每个元素通过两个下标来存取。

Array2D ADT

  • Array2D(nrows, ncols): 创建一个 nrows 行,ncols 列的二维数组,并初始化每个元素为 None
  • numRows(): 返回行数
  • numCols(): 返回列数
  • clear(value): 将所有元素的值设为 value
  • getitem(row, col): 通过下标法 y=x[1,2] 来访问元素
  • setitem(row, col, value): 设置元素值

Array2D 的实现

通常有 2 种数据组织方法:

  • 使用一个一维数组,将行列上的每个元素位置映射到数组的相应位置
  • 使用数组的数组实现

下面的实现采用了数组的数组方法,将二维数组中的每一行存储在一维数组中,然后再创建一个数组,用来保存行数组(即该数组是数组的数组)。Array2D 的抽象和物理存储视图如下:

有些语言的实现中,可以存取每个行,从而对每个元素的访问使用 x[r][c] 进行。为了隐藏实现细节,我们的实现不暴露行数组,从而对每个元素的访问使用 x[r,c] 进行。

实现如下:

class Array2D:def __init__( self, nrows, ncols ):# Create a 1-D array to store an array reference for each row.self._theRows = Array( nrows )# Create the 1-D arrays for each row of the 2-D array.for i in range( nrows ):self._theRows[i] = Array( ncols )def numRows( self ):return len( self._theRows )def numCols( self ):return len( self._theRows[0] )# Clears the array by setting every element to the given value.def clear( self, val ):for row in range( self.numRows() ):self._theRows[row].clear( val )def __getitem__( self, xy ):assert len( xy ) == 2, "Invalid number of array subscripts."row = xy[0]col = xy[1]assert row >= 0 and row < self.numRows() and \col >= 0 and col < self.numCols(), "Array subscript out of range."the1arr = self._theRows[row]return the1arr[col]def __setitem__( self, xy, val ):assert len( xy ) == 2, "Invalid number of array subscripts."row = xy[0]col = xy[1]assert row >= 0 and row < self.numRows() and \col >= 0 and col < self.numCols(), "Array subscript out of range."the1arr = self._theRows[row]the1arr[col] = val
实现元素的存取

__getitem__(self, index)__setitem__(self, index. value) 这两个函数定义参数中, 只有一个 index 参数,但这不会限制只能使用一个下标。当使用多个下标时,如 y = x[i,j],多个下标会组合成一个 tuple 作为 index 参数传入。

Matrix ADT

矩阵是标量值的集合,这些值以行和列的形式组织成一个固定大小的矩形网格中。

  • Matrix(nrows, ncols): 创建一个 nrows 行和 ncols 列的矩阵
  • numRows(): 返回行数
  • numCols(): 返回列数
  • getitem(row, col): 返回元素
  • setitem(row, col, scalar): 设置元素值
  • scaleBy(scalar): 矩阵中的每个元素都乘该值,操作后矩阵本身将被修改
  • transpose(): 返回一个转置矩阵
  • add(rhsMatrix): 创建并返回一个新矩阵。这两个矩阵大小必须相同
  • subtract(rhsMatrix): 相减
  • multiply(rhsMatrix): 相乘。

Matrix 的实现

一般用二维数组来实现矩阵。

实现如下:

from array import Array2Dclass Matrix:def __init__( self, nrow, ncols ):self._theGrid = Array2D( nrow, ncols )self._theGrid.clear( 0 )def numRows( self ):return self._theGrid.numRows()def numCols( self ):return self._theGrid.numCols()def __getitem__( self, xy ):return self._theGrid[ xy[0], xy[1] ]def __setitem__( self, xy, scalar ):self._theGrid[ xy[0], xy[1] ] = scalardef scaleBy( self, scalar ):for r in xrange( self.numRows() ):for c in xrange( self.numCols() ):self[r, c] *= scalardef transpose( self ):newMatrix = Matrix( self.numCols(), self.numRows() )for r in xrange( self.numRows() ):for c in xrange( self.numCols() ):newMatrix[c, r] = self[r, c]return newMatrixdef add( self, rhsMatrix ):assert rhsMatrix.numRows() == self.numRows() and \rhsMatrix.numCols() == self.numCols(), \"Matrix sizes not compatible for the add operation."newMatrix = Matrix( self.numRows(), self.numCols() )for r in xrange( self.numRows() ):for c in xrange( self.numCols() ):newMatrix[r, c] = self[r, c] + rhsMatrix[r, c]return newMatrixdef subtract( self, rhsMatrix ):assert rhsMatrix.numRows() == self.numRows() and \rhsMatrix.numCols() == self.numCols(), \"Matrix sizes not compatible for the add operation."newMatrix = Matrix( self.numRows(), self.numCols() )for r in xrange( self.numRows() ):for c in xrange( self.numCols() ):newMatrix[r, c] = self[r, c] - rhsMatrix[r, c]return newMatrixdef multiple( self, rhsMatrix ):assert self.numCols() == rhsMatrix.numRows(), \"Matrix sizes not compatible for the multiple operation."newMatrix = Matrix( self.numRows(), rhsMatrix.numCols() )for r in xrange( self.numRows() ):for rhsC in xrange ( rhsMatrix.numCols() ):tmp = 0for c in xrange( self.numCols() ):tmp += self[r, c] * rhsMatrix[c, r]newMatrix[r, rhsC] = tmpreturn newMatrix

应用: 游戏人生

The game of Life 是由英国数学家 John H. Conway 发明的,它能模拟生物群落的兴衰更替。该游戏可用来观察一个复杂的系统或模式如何能从一组简单的规则演化而来。

游戏规则

该游戏使用一个不限大小的矩形网格,其中的每个单元格要么是空的,要么被一个有机体占据。被占据的单元格被视作是活的,而空的单元格被视作是死的。游戏的每次演进,都会基于当前的单元格布局,创造新的“一代”。下一代中的每个单元格状态是根据以下规则确定的:

  1. 若某单元格是活的,并且有 2 或 3 个活的邻居,那么它在下一代也保持活。每个单元格有 8 个邻居。
  2. 若某单元格是活的,但它没有活的邻居,或只有一个活邻居,它在下一代会死于孤立。
  3. 一个活单元格,若有 4 个或更多个活邻居,它在下一代会死于人口过剩。
  4. 一个死单元格,当且仅当只有 3 个活邻居时,会在下一代重生。

用户先初始化配置,即指定哪些单元格是活的,然后运用以上的规则,生成下一代。可以看到,一些系统可能最终会消亡,而有些最终会进化成 “稳定” 状态。例如:

设计方案

一个网格 life grid 用来表示和存储游戏区。网格包含一组矩形单元格,并分成有限大小的行和列。

  • LifeGrid(nrows, ncols): 创建一个新的游戏网格。所有单元格设置为空(死)。
  • numRows(): 返回网格行数。
  • numCols(): 返回网格列数。
  • configure(coordList): 配置网格以进行下一代的演化。参数是一个 (row, col) 的序列,每一个元组表示该位置的单元格是活的。
  • clearCell(row, col): 设置单元格为空(死)。
  • setCell(row, col): 设置单元格为活。
  • isLiveCell(row, col): 返回一个布尔值,表示某个单元格是否包含一个活的有机体。
  • numLiveNeighbors(row, col): 返回某个单元格的所有活邻居个数。对于边缘的单元格,落在边缘外的邻居都认为是死的。

实现

使用一个二维数组来表示网格。每个单元格的状态使用 0 和 1 表示,0 表示死,1 表示活。这样在统计单元格的活邻居总数时,只需要将邻居的状态相加即可。实现时网格的大小是限定的,如果大小超出了,在运行过程中可以重新创建一个新的网格。

# life.py
from array import Array2Dclass LifeGrid:DEAD_CELL = 0LIVE_CELL = 1def __init__( self, nrows, ncols ):self._grid = Array2D( nrows, ncols )self.configure( list() )def numRows( self ):return self._grid.numRows()def numCols( self ):return self._grid.numCols()def configure( self, coordList ):for i in range( self.numRows() ):for j in range( self.numCols() ):self.clearCell(i, j)for coord in coordList:self.setCell( coord[0], coord[1] )def isLiveCell( self, row, col ):return self._grid[ row, col ] == LifeGrid.LIVE_CELLdef clearCell( self, row, col ):self._grid[ row, col ] = LifeGrid.DEAD_CELLdef setCell( self, row, col ):self._grid[ row, col ] = LifeGrid.LIVE_CELLdef numLiveNeighbors( self, row, col ):nrows = self.numRows()ncols = self.numCols()liveNum = 0for i in range( row-1, row+2 ):for j in range( col-1, col+2 ):if ( 0 <= i < nrows ) and ( 0 <= j < ncols ):liveNum += self._grid[i, j]liveNum -= self._grid[ row, col ]return liveNumfrom life import LifeGrid# Define the initial configuration of live cells.
INIT_CONFIG = [ (0, 0), (0, 1), (1, 0), (1, 2), (3, 2), (3, 4), (5, 4), (5, 6), (7, 6), (7, 8), (9, 8), (9, 10), (11, 10), (11, 12), (12, 11), (12, 12)]# Indicate the number of generations
#NUM_GENS = 8def main():GRID_WIDTH = int( raw_input( "Grid width:" ) )GRID_HEIGHT = int( raw_input( "Grid height:" ) )NUM_GENS = int( raw_input( "Nbr of generations to evolve:" ) )grid = LifeGrid( GRID_WIDTH, GRID_HEIGHT )grid.configure( INIT_CONFIG )# Play the game.draw( grid )for i in range( NUM_GENS ):evolve( grid )draw( grid )def evolve( grid ):liveCells = list()for i in range( grid.numRows() ):for j in range( grid.numCols() ):neighbors = grid.numLiveNeighbors( i, j )# 1. If a cell is alive and has either two or three live neighbors, the cell remains alive in the next generation. # The neighbors are the eight cells immediately surrounding a cell: vertically, horizontally, and diagonally.  # 2. A living cell that has no live neighbors or a single live neighbor dies from isolation in the next generation.# 3. A living cell that has four or more live neighbors dies from overpopulation in the next generation.# 4. A dead cell with exactly three live neighbors results in a birth and becomes alive in the next generation.# All other dead cells remain dead in the next generation.if (neighbors == 2 and grid.isLiveCell( i, j )) or \(neighbors == 3):liveCells.append( (i, j) )grid.configure( liveCells )def draw( grid ):printfor i in range( grid.numRows() ):for j in range( grid.numCols() ):if grid.isLiveCell( i, j):print '@',else:print '.',printmain()

参考:

  • Data Structures and Algorithms Using Python: Arrays

转载于:https://www.cnblogs.com/oneTOinf/p/11521438.html

数据结构与算法-ADT-Array相关推荐

  1. 数据结构与算法 -- 栈 ADT

    这两天翻了下数据结构与算法分析.严蔚敏的数据结构.C和指针.C Primer Plus这些本书,受益很多.不过大多的示例不够完整,需要自己动手编写程序.又看了遍培训时的笔记,虽然很糙但是精华的部分还是 ...

  2. java array 元素的位置_数据结构与算法:动态图解十大经典排序算法(含JAVA代码实现)...

    点击上方"JAVA",星标公众号 重磅干货,第一时间送达 本文将采取动态图+文字描述+正确的java代码实现来讲解以下十大排序算法: 冒泡排序 选择排序 插入排序 希尔排序 归并排 ...

  3. 邓俊辉 数据结构与算法C++版 第十三章 串 ADT

    邓公数据结构与算法 第十三章 串 ADT 定义和特点 术语 ADT接口实现 模式匹配 问题与需求 算法测试方法 蛮力匹配 构思 蛮力匹配:版本1 蛮力匹配:版本2 蛮力匹配:性能分析 KMP算法 ne ...

  4. 数据结构与算法 -- 二叉树 ADT

    树的类型有很多,这里我们只讲二叉树. 一.二叉树的基本概念 1.什么是二叉树 在计算机科中,二叉树是每个节点最多有两个子树的树结构.通常子树被称作"左子树"和"右子树&q ...

  5. 数据结构与算法(4)——优先队列和堆

    前言:题图无关,接下来开始简单学习学习优先队列和堆的相关数据结构的知识: 前序文章: 数据结构与算法(1)--数组与链表(https://www.jianshu.com/p/7b93b3570875) ...

  6. 一文带你认识30个重要的数据结构和算法

    摘要:掌握DSA意味着你能够使用你的计算和算法思维来解决前所未见的问题.通过了解它们,您可以提高代码的可维护性.可扩展性和效率. 本文分享自华为云社区<30 个重要数据结构和算法完整介绍> ...

  7. 数据结构与算法基础01:绪论

    目录 1. 程序设计 = 数据结构 + 算法 2. 基本概念和术语 2.1 数据 2.2 数据元素 2.3 数据对象 2.4 数据结构 3. 逻辑结构和物理结构 3.1 逻辑结构 3.2 物理结构(存 ...

  8. python中文教程github_GitHub - Virile-Tao/python_data_structures_and_algorithms: Python 中文数据结构和算法教程...

    Python 算法与数据结构视频教程 课程简介 数据结构和算法是每个程序员需要掌握的基础知识之一,也是面试中跨不过的槛.目前关于 Python 算法和数据结构的系统中文资料比较欠缺, 笔者尝试录制视频 ...

  9. java数据结构与算法之顺序表与链表深入分析

    转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/52953190 出自[zejian的博客] 关联文章: java数据结 ...

  10. 数据结构与算法(C语言)

    第一章: 数据结构绪论 1.什么是程序:程序 = 数据结构 + 算法 2.逻辑结构&物理结构的区别用法 基本的目标就是将数据及其逻辑关系存储到计算机的内存中 一:逻辑结构: 逻辑结构是指数据对 ...

最新文章

  1. 天大本科生论文入选CVPR 2022,实现深度学习长尾分类新SOTA
  2. ad走线画直线_作为立体几何的热点,直线与平面的平行关系,到处都是考试的影子...
  3. XP系统,无法创建新的网络连接
  4. JavaScript 工作原理(一):引擎,运行时,调用堆栈
  5. Access中出现改变字段“自己主动编号”类型,不能再改回来!(已解决)
  6. 中国香皂行业产量份额预测与消费需求商机研究报告2022年
  7. 防火墙(16)——SNAT和DNAT,DNAT实践
  8. 19.Silverlight调用webservice上传多个文件
  9. 【转】Unix环境高级程序设计入门----文件系统的相关编程(上)
  10. mysql怎样搞一个项目_程序员如何快速上手一个自己不太熟悉的新项目?有什么技巧?...
  11. javascript实现java的StringBuffer功能
  12. 浮点数 字符串 java_Java如何将浮点数转换为字符串
  13. 读取自定义配置文件属性值
  14. 33. Pandas计算同比环比指标的3种方法
  15. python文件夹排序笔记
  16. R语言 重命名指定列
  17. 大脑神经网络记忆原理图,记忆力机制的神经网络
  18. 基于GIS的三维智慧警务系统
  19. --hot 和 --inline的区别
  20. 如何快速将显示未签收的单号物流归类为签收件

热门文章

  1. 安卓系统挂载NTFS格式硬盘_Mac 读写 NTFS硬盘管理开源工具NTFSTool
  2. angular8多选框实现点击整行任意位置<tr>就可以选中多选框
  3. Hbase搭建-基于hadoop3--并且解决了hbase error: KeeperErrorCode = NoNode for /hbase/master错误
  4. c++ vs release没有exe_未来安全 | 第一次Geant4培训总结 | 有没有你关注的问题呢?...
  5. 用生动的例子花式解释:python类中一定需要有 __init__方法么?没有会怎样?
  6. 【HDU - 4348】To the moon(主席树,区间更新)
  7. 【2019浙江省赛 - K 】Strings in the Pocket(马拉车,思维)
  8. 【hihocoder - offer编程练习赛60 C】路径包含问题(LCA,树上倍增)
  9. 动手学PaddlePaddle(4):MNIST(手写数字识别)
  10. mysql 如何调用函数结果_MySQL自定义函数调用不出结果