数据结构与算法-ADT-Array

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 的抽象和物理视图如下:

listUsingArrayView.png

追加元素 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 的抽象和物理存储视图如下:

array2dView.png

有些语言的实现中,可以存取每个行,从而对每个元素的访问使用 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 个活邻居时,会在下一代重生。

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

gamelife_stable1.png

gamelife_stable2.png

设计方案

一个网格 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/447803.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端VUE工程不占用80端口,浏览器不带端口访问VUE项目的实现

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1.需求&#xff1a;直接域名访问项目&#xff0c;不用IP&#xff0c;也不带端口号。 1&#xff09;访问项目方法通常是 IP&#xff1a;…

ResourceDictionary主题资源替换(二) :编译期间,替换主题资源

之前的ResourceDictionary主题资源替换&#xff08;一&#xff09;通过加载顺序来覆盖之前的主题资源&#xff0c;介绍了WPF框架对ResourceDictionary资源的合并规则。 此篇介绍一种在编译期间&#xff0c;实现资源替换的方案 前言 如下图&#xff0c;项目中存在俩个主题资源字…

解决 idea 中 jsp 修改后页面不生效

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1.问题描述&#xff1a;idea 编辑 jsp , 修改好后在 浏览器访问却发现页面完全无变化 。 2.解决&#xff0c;要在 idea 中作如下设置&a…

解决 :IDEA 修改代码后 Local Changes 中没有提示待提交文件,代码自动提交了

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 通常修改代码后 会在 Local Changes 中提示修改过的文件&#xff0c;如下&#xff1a; 2. 我的情况是 &#xff0c;在这个界面中什么…

解决:Caused by: java.lang.UnsupportedOperationException: null

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1.报错&#xff1a; 严重: Servlet.service() for servlet [lbd-institution] in context with path [/ins] threw exception [Reques…

IntelliJ IDEA 设置代码检查级别

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 设置代码检查等级   IntelliJ IDEA中最右下角的小按钮可以设置当前编辑文档的代码检查等级&#xff0c;如图   Inspections 为最高等…

spring 中构造Constructor、@Autowired、@PostConstruct、静态方法的执行顺序 (@PostConstruct 说明)

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 关于注解 PostConstruct public interface PostConstructPostConstruct 注释用于在依赖关系注入完成之后需要执行的方法上&#xff…

联合索引:创建、删除、查看 (解决报错:Duplicate key name)

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 创建联合索引&#xff1a; CREATE INDEX idx_xxx_stitution ON xxx_order (status,institution_code) idx_xxx_stitution &#x…

mybatis 中 Example 的使用 :条件查询、排序、分页(三种分页方式 : RowBounds、PageHelpler 、limit )

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 import tk.mybatis.mapper.entity.Example;import com.github.pagehelper.PageHelper;...Overridepublic List<Repayxxx> listRep…

解决: IDEA 代码 commit 后,Local Changes 中代码依旧在,提交失败,报错:is out of date

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 代码提交后 Local Changes 中的代码未消失。查看 Event log 发现提交失败。 如下 红框中位置就是 Event log&#xff0c;或者点击…

什么是响应式布局设计

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 看一个例子&#xff1a;Mashable 的首页&#xff1a; 浏览器窗口最大化时&#xff1a; 缩小浏览器窗口&#xff1a; 再缩小&#x…

git 提交 不用输入用户名、密码的方法(GIT免密提交)

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 我以前设置过&#xff0c;但最近把项目换地方了&#xff0c;环境也改了些配置&#xff0c;发现不能免密 push 了。 设置方法如下&#…

docker启动,重启,关闭命令

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 --------------------- 转自&#xff1a;https://blog.csdn.net/easternunbeaten/article/details/80463837

十二个生活习惯,增加你的心灵压力

随着生活节奏的加快&#xff0c;很多人抱怨压力越来越大。美国《赫芬顿邮报》近日载文指出&#xff0c;一些压力是外在压力&#xff0c;而更多的压力来自我们自身。以下就是在不知不觉中增加自身压力的习惯。 忘记每日大笑 如果你想不起来上次捧腹大笑的时间&#xff0c;你就该…

VisualCode 查看代码历史版本、还原代码到既定历史版本

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 我想要类似 eclipse 查看并还原代码到既定历史版本的效果。 1. 安装插件&#xff1a;Local History &#xff0c;点击右下角 Install 就…

解决: cp -rf 命令中参数 -f 失效 ( 依旧要手动确认 )

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 运行 cp -rf 命令时依旧给出无数提示&#xff0c;要求确认&#xff0c;很是麻烦&#xff0c;如下图&#xff1a; 2. 可能原因&#…

FreeSql (二十四)Linq To Sql 语法使用介绍

原本不支持 IQueryable 主要出于使用习惯的考虑&#xff0c;如果继承 IQueryable&#xff0c;编写代码的智能总会提示出现一堆你不想使用的方法&#xff08;对不起&#xff0c;我有强迫症&#xff09;&#xff0c;IQueryable 自身提供了一堆没法实现的方法&#xff0c;还有外部…

前后端分离工程实现 (VUE、JAVA)、附全部源码

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 整个工程基本情况简述&#xff1a; 前端工程语言&#xff1a;vue &#xff08;node.js&#xff09; 后端工程语言&#xff1a;java…

聊聊并发——生产者消费者模式

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。 为什么要使用生产者和消费者模式 在线程世界里&#xff0c;生产者就是生产数据的线程&#xff0c;消费者就是消费数据的线程。在…

多个 VUE 前端工程部署设置、nginx 代理配置

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 PS&#xff1a;早期 我只有一个 VUE 前端工程&#xff1a;gentle-vue &#xff0c;加一个 java 后端工程&#xff1a;gentle &#xff0…