一維數組是連續元素的集合,其中的每一個元素均可以經過惟一的整數下標來存取。數組的大小在建立後不能修改。html
ADT 定義:node
Python 中的許多數據類型及類實際上都是基於低層 C 語言中的相關類型實現的。Python 標準庫中的 ctypes 模塊可用來訪問 C 語言中的各類類型及 C 類庫中的功能。使用 ctypes 提供的大多數功能都要求理解一些 C 語言知識。python
相似 Python 實現 string, list, tuple 和 dict,咱們經過 ctypes 建立一個數組,其中的元素都是 Python 對象引用:web
for i in range(5):
slots[i] = None
這個數組必須先初始化後才能訪問,否則會拋出異常,如 slots[0]
會拋出異常,初始化以下:數組
import ctypes
class Array:
def __init__( self, size ):
assert size > 0, "Array size must be > 0"
self._size = size
PyArrayType = ctypes.py_object * size
self._elements = PyArrayType()
self.clear( None )
def __len__( self ):
return self._size
def __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 ] = val
def clear( self, val ):
for i in xrange( self._size ):
self._elements[ i ] = val
def __iter__( self ):
return _ArrayGenerator( self._elements, self._size )
def _ArrayGenerator( elements, size ):
for i in range( size ):
yield elements[i]
Array 的實現以下:markdown
pyList = [4, 12, 2, 34, 17]
Python List 也是經過低層的 C 語言類型實現的,它是一個可修改的序列容器,其大小能夠隨着元素的添加和刪除自動改變。數據結構
pyListA = [34, 12] pyListB = [4, 6, 31, 9] pyListA.extend(pyListB)
以上代碼將調用 list()
構造器,構造器將建立一個數組結構用來存儲列表中的元素。實際上初始建立的數組大小會大於所需的容量,這樣便於之後的擴展操做。app
用於存儲列表元素的數組其實是剛纔建立的數組中的一個子數組 subarray。len(lst)
返回該子數組的長度,而整個數組的長度爲 capacity
。 用數組實現的 Python List 的抽象和物理視圖以下:ssh
當數組容量足夠時,新元素將追加到數組中,而且 list 的 length
域也相應增長。ide
當數組満時,List 會進行自動擴展,即:
新建數組的大小是根據原數組的大小肯定的,好比說,新數組的大小定爲原數組大小的 2 倍 。 擴展後再在數組後追加元素。
好比:
pyList.insert(3, 79)
當 pyListA 中的數組容量不夠時,List 會自動進行如 append 進行的相似數組擴展操做。
好比:
pyList.pop(0) # remove the first item
pyList.pop() # remove the last item
當位置 3 已經有元素時,位置 3 及其後面的全部元素都將後移一個位置,並在位置 3 插入新元素。當數組容器不夠,會進行和上面類似的數組擴展操做。
好比:
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
刪除後,若是後面還有元素,那麼被刪除元素後面的全部元素將前移一個位置,以便填充刪除後的空位。
固然,若是刪除後的數組空位過多,也會進行相對應的收縮數組操做。
Slice 會建立一個新的 List。
它將數據組織成行和列,相似於表格。每一個元素經過兩個下標來存取。
y=x[1,2]
來訪問元素一般有 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 參數傳入。
矩陣是標量值的集合,這些值以行和列的形式組織成一個固定大小的矩形網格中。
通常用二維數組來實現矩陣。
實現以下:
from array import Array2D
class 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] ] = scalar
def scaleBy( self, scalar ):
for r in xrange( self.numRows() ):
for c in xrange( self.numCols() ):
self[r, c] *= scalar
def 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 newMatrix
def 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 newMatrix
def 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 newMatrix
def 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 = 0
for c in xrange( self.numCols() ):
tmp += self[r, c] * rhsMatrix[c, r]
newMatrix[r, rhsC] = tmp
return newMatrix
The game of Life 是由英國數學家 John H. Conway 發明的,它能模擬生物羣落的興衰更替。該遊戲可用來觀察一個複雜的系統或模式如何能從一組簡單的規則演化而來。
該遊戲使用一個不限大小的矩形網格,其中的每一個單元格要麼是空的,要麼被一個有機體佔據。被佔據的單元格被視做是活的,而空的單元格被視做是死的。遊戲的每次演進,都會基於當前的單元格佈局,創造新的「一代」。下一代中的每一個單元格狀態是根據如下規則肯定的:
用戶先初始化配置,即指定哪些單元格是活的,而後運用以上的規則,生成下一代。能夠看到,一些系統可能最終會消亡,而有些最終會進化成 「穩定」 狀態。例如:
一個網格 life grid 用來表示和存儲遊戲區。網格包含一組矩形單元格,並分紅有限大小的行和列。
使用一個二維數組來表示網格。每一個單元格的狀態使用 0 和 1 表示,0 表示死,1 表示活。這樣在統計單元格的活鄰居總數時,只須要將鄰居的狀態相加便可。實現時網格的大小是限定的,若是大小超出了,在運行過程當中能夠從新建立一個新的網格。
# life.py
from array import Array2D
class LifeGrid:
DEAD_CELL = 0
LIVE_CELL = 1
def __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_CELL
def clearCell( self, row, col ):
self._grid[ row, col ] = LifeGrid.DEAD_CELL
def setCell( self, row, col ):
self._grid[ row, col ] = LifeGrid.LIVE_CELL
def numLiveNeighbors( self, row, col ):
nrows = self.numRows()
ncols = self.numCols()
liveNum = 0
for 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 liveNum
from 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 = 8
def 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 ):
print
for i in range( grid.numRows() ):
for j in range( grid.numCols() ):
if grid.isLiveCell( i, j):
print '@',
else:
print '.',
print
main()
參考: