内容正文:
01
数组的概念与特性
1
所处位置
(下标)
数据本身
(元素)
0 1 2 3
李彤 张强 胡洁 杜刚
常见的数据结构——数组
现实中表示一批数据,有时不仅需要描述数据对象本身,还需要描述数据所处的位置或者数据之间的前后顺序关系,便可以用数组这种数据结构来实现(存储的都是同种数据类型)
a[0]=‘李彤’
a[1]=‘张强’
a[2]=‘胡洁’
a[3]=‘杜刚’
第一个是李彤
第二个是张强
第三个是胡洁
第四个是杜刚
进一步抽象
a [3]
a
[3]
数组名
下标(索引)
李彤 张强 胡洁 杜刚
a[0]
a[1]
a[2]
a[3]
a
数组是由相同类型的变量构成的一个序列。
数组使用数组名命名,并用下标或索引区分数组内的各个变量。
由数组名和下标组成数组的各个变量称为数组的分量也称数组元素。
创建数组时系统会分配一块连续的存储空间,每个数组元素按照下标顺序依次存储(顺序存储)
数组的存储结构
也可以通过变量名后面的下标依次按顺序遍历序列中的每个元素。
例:用sg数组来存放身高信息,sg=[165,169,185,179,172,191]
sg[0]=165(下标从0开始)
用数组组织数据时,可以快速通过下标精准地访问序列中的某个元素
方法一:
sg=[165,169,185,179,172,191]
for i in range(len(sg)):
print(sg[i])
方法二:
sg=[165,169,185,179,172,191]
for i in sg:
print(i)
5
一维数组
一维数组:只有一个下标的数组称为一维数组,一维数组适合用来表示具有线性特征的数据序列。
d[i]
d[0] d[1] d[2]
2 5 6
数组名
下标(索引)
qp[i][j]
d[0][0] d[0][1] d[0][2]
0 1 0
数组名
下标(索引)
二维数组
二维数组:二维数组中的数据元素有行、列两个维度的元素,需要两个下标。
第一个下标表示行位置
第二个下标表示列位置
二维数组的存储方式:
行优先存储方式
列优先存储方式
0
1
0
0
1
2
2
0
…
[0][0]
[0][1]
[0][2]
[0][3]
[1][0]
[1][1]
[1][2]
[1][3]
...
0
1
0
0
1
2
2
2
…
[0][0]
[1][0]
[2][0]
[3][0]
[0][1]
[1][1]
[2][1]
[3][1]
...
行优先存储
列优先存储
数组的特性
(1)数组元素的数据类型相同
系统会根据数组的下标及数组中存储的数据类型快速得到其存储位置并访问。
(2)通过数组名和下标对数组元素进行访问
例如a[i],可以通过这种形式可以快速访问任意位置的数组元素。
(3)存储空间固定不变
数组创建后,存储空间不变。即数组中的某些元素删除后,但其占用的空间继续保留,可能造成空间浪费和空间不够导致数据丢失的现象。
b[0] b[1] b[2] b[3] b[4]
20 15 14 10 4
b
b[0] b[1] b[2] b[3] b[4]
20 15 14 4
b
删除b[3]
(1)静态数组
定义一个数组后系统会根据每个数组元素的数据类型和总元素个数,在内存中开辟一批地址连续且空间固定的存储空间。
(2)动态数组:
在声明时没有确定数据规模的数组,可以在任何时候改变数据规模。
(3)在Python语言中没有数组这种结构,但是有更灵活的数据结构-----列表
数组的特性
在python中使用列表来模拟数组,其所占空间大小可以用内置函数len()来获取。
例:a[0]*10
例:a=[]
区别 数组 列表
元素类型
存储结构
… … …
一致
可以不一致
顺序(连续)存储
链式(不连续)存储
当列表中存储的元素类型保持一致,并且只考虑逻辑结构时,
可以把列表看成数组。
数组≠列表
数组的创建
数组元素的访问
数组元素的插入
数组元素的删除
数组的基本操作
01
12
数组的创建
·创建列表实现一维数组
(1)使用 [ ] 直接创建
a = [1, 2, 3]
(2)使用 list( ) 函数创建
a = list( ‘Key’ )
(3)使用 * 创建
a = [ 0 ] * 4
(4)使用 for 循环创建
a = [ 0 for i in range( 4 )]
a = [ 1, 2, 3 ]
a = [ “K”,”e”,”y” ]
a = [ 0, 0, 0, 0 ]
a = [ 0, 0, 0, 0 ]
可以理解为:
for i in range(4):
a.append(0)
num = [[0,0,0],[0,0,0],[0,0,0]]
num = [[0 for i in range(3)] for j in range(3)]
for i in range(len(num)):
print(num[i])
num = [[0]*3 for j in range(3)]
for i in range(len(num)):
print(num[i])
num = [[0]*3]*3
num[1][2] = 1
for i in range(len(num)):
print(num[i])
❌
数组的创建
·创建列表实现二维数组
(1)使用 [ ] 直接创建
(2)使用 for 循环创建(列表推导式)
b=[[0]*3]*3或b=[[0,0,0]]*3
b[1][1]=1
想象中的b数组
实际上的b数组
数组的创建
[[0,0,0],[0,0,0],[0,0,0]]
[[0,0,0],[0,1,0],[0,0,0]]
[[0,1,0],[0,1,0],[0,1,0]]
浅拷贝
15
1.有如下Python程序段:
a=[[0]*4]*3
b=[[0]*4 for i in range(3)]
a[2][3]=8
b[2][3]=8
则程序执行后,下列说法正确的是( )
A.a[0][3]的值为0,b[0][3]的值为0
B.a[0][3]的值为0,b[0][3]的值为8
C.a[0][3]的值为8,b[0][3]的值为0
D.a[0][3]的值为8,b[0][3]的值为8
练习
C
3.有如下Python程序段:
a=[[0]*3 for i in range(4)]
for i in range(len(a)):
for j in range(len(a[0])):
a[i][j] = i*len(a[0])+j+1
print(a[2][2])则程序执行后,a[2][2]的值为( )
A.5 B.6 C.8 D.9
2.有如下Python程序段:
a=[[1]*3]*4
a[1][2]=6
则程序执行后,a[3][2]的值为( )
A.0 B.1 C.4 D.6
D
练习
D
练习
4.有如下Python程序段:
a = [[i+1 for i in range(4)] for j in range(3)]
for i in range(3):
for j in range(4):
a[i][j] = a[i][j]+4*i
则程序执行后,a[1][2]的值为( )
A.2 B.4 C.7 D.8
C
数组元素的访问
数组名+下标访问
一维数组访问第i个元素:num[i-1]
二维数组访问第i行第j列个元素:num[i-1][j-1]
访问一维数组
访问二维数组
from random import randint
num = [randint(1,10) for i in range(5)]
print(num)
print(num[3])
num = [[1,2,3],[4,5,6],[7,8,9]]
print(num[1][2])
一维数组
数组名[下标访问]
想要取到数组中第三个元素:
想要取到数组中第i个元素:
想要访问数组中第2到第4个元素切片访问:
二维数组
数组名[行下标][列下标]
想要取到数组中第2行第3列的元素:
访问第i行第j列的元素表示为:
a[2]
a[1:4]
a[1][2]
a[i-1][j-1]
数组元素的访问
a[i-1]
20
·二维数组
例如:a = [ 1, 2, 3, 4, 5, 6]
a[ 0 ] =
a[ 3 ] =
·一维数组
例如:a = [ [1, 2, 3], [4, 5, 6] ]
a[ 0 ][ 1 ] =
a[ 1 ][ 2 ] =
数组元素的访问
数组元素的访问
物理地址计算
行优先:
LOC(a[i][j])=LOC(a[0][0])+(i*C+j)*s
列优先:
LOC(a[i][j])=LOC(a[0][0])+(j*R+i)*s
0 1 … C-1
1 …
… … a[i][j] …
R-1 …
C为最大列数
R为最大行数
s代表每个元素存储空间
牛刀小试
一个数组的第一个元素的存储位置为1000(表示在第1000个字节处),每个元素所占空间大小为8个字节,则第5个元素的位置是?
1000 B. 1040 C. 1032 D. 1256
C
假设每个元素占用的内存空间是c个存储单元,那么线性表中第i个元素ai的存储位置可以由a1推算得出LOC(a)=LOC(a1)+(i-1)*c
数组元素的访问
1.在二维数组a中,每个元素所占空间大小为8个字节,行下标i从0到4,列下标j从0到5,从首地址SA开始连续存放在存储器内,存放该数组需要的存储空间为( )
A.20B B.30B C.160B D.240B
D
2.二维数组a中,每个元素所占空间大小为8个字节,行下标i从0到5,列下标j从0到9,从首地址SA开始连续存放在存储器内,该数组按行存放时,元素a[2][3]的起始地址为__________
SA+184
如果用列优先存储呢?
SA+160
算法设计:
①初始化3个数组a,b,c,元素个数分别为n,m和n+m。数组a和数组b用来存储已有的两个有序数据(降序),数据使用随机函数randint(start,end)产生;数组c用于保存合并后的所有数据(降序),所有数组元素的值初始化为0。
②使用变量i指向数组a当前未处理数据中要处理的数据元素的位置,初始化为0;变量j指向数组b当前未处理数据中要处理的数据元素的位置,初始化为0;变量k指向数组c中可加入元素的位置,初始化为0。
数组元素的访问
算法设计:
③重复以下操作,直至数组a或数组b中的数据元素全部合并入数组c中:比较a[i]和b[j]的大小,若a[i]≥b[j],则将a[i]放入数组c中,并将i和k的值增加1;否则,将b[j]放入数组c中,并将j和k的值增加1。
④如果数组a或数组b中尚有未处理的数据元素,那么将剩余数据元素按原有顺序依次存入数组c中,合并完成,输出数组c。
数组元素的访问
程序 备注
from random import randint
a = [0]*20
b = [0]*15
c = [0]*35 初始化a、b、c三个数组,数组长度分别为20、15、35。
a[0] = randint(95, 100)
for i in range(1, 20): # 随机产生降序数据序列一
a[i] = a[i-1] - randint(1, 5) 生成a数组序列:
[99, 97, 95, 94, 90, 87,83,79, 78, 73, 71, 69, 67, 66, 61,60, 56, 55, 52, 51]
b[0] = randint(95, 100)
for i in range(1, 15): # 随机产生降序数据序列二
b[i] = b[i-1]-randint(1, 5) 生成b数组序列:
[99, 96, 94, 91, 90, 88, 87,
82, 80, 79, 75, 73, 70, 66,62]
print("原始数据序列一为:")
print(a)
print("原始数据序列二为:")
print(b)
数据合并问题
程序 备注
while i < 20 and j < 15: #合并数据至某数组合并完成
if a[i] >= b[j]:
c[k] = a[i]
i, k = i+1, k+1
else:
c[k] = b[j]
j, k = j+1, k+1 C数组序列:j=15,i=14
[99,99,97,96,95,94,94,91,90,90,88,87,87,83,82,80,79,79,78,75,73,73,71,70,69,67,66,66,62,0,0,0,0,0,0]
while i < 20: #当数据序列一中还有数据时的处理
c[k] = a[i]
i, k = i+1, k+1 C数组序列:j=15,i=20
[99,99,97,96,95,94,94,91,90,90,88,87,87,83,82,80,79,79,78,75,73,73,71,70,69,67,66,66,62,61,60,56,55,52,51]
while j < 15: #当数据序列二中还有数据时的处理
c[k] = b[j]
j, k = j+1, k+1
print("合并后的数据序列为:
", c) 输出合并后的C数组序列
数据合并问题
·数组添加元素
思想:
当需要在数组中某个位置中插入一个新元素时,必须先将该位置及其后的所有数据向后移动一个位置,最后在修改该位置上的数据为新数据。
·数组添加元素
data1 data2 data3 data4 data5
a
pos
n-1
·列表添加元素
1)使用【+】运算符
例如:
listname = [1,2,3]
listname = listname + [7]
实际上,使用“+”运算符,并不是真的添加列表中的元素,而是创建一个新的列表,把原列表中的元素和新元素依次复制到新列表的内存空间里。因为有大量元素的复制,所以该操作的速度较慢。在涉及到大量数据的操作时,不建议使用该方法。
相当于以下操作:
listname = [1,2,3]
listname = [1,2,3,7]
·列表添加元素
2)使用【append】方法
在当前列表尾部追加元素。它会把添加的元素作为一个整体来操作。
格式:
listname.append(obj)
1. listname:要添加元素的列表
2. obj :要添加的数据,它可以是单个元素,也可以是列表、元组等
例如:
listname = [1,2,3]
listname.append( 7 )
listname.append( [7,8] )
注意:该方法是在原列表中修改,所以使用该方法添加元素的操作速度较快。
listname = [1,2,3,7]
listname = [1,2,3,[7,8]]
·列表添加元素
3)使用【extend】方法
在当前列表尾部追加元素,但不会把列表或者元祖视为一个整体,而是把它们包含
的元素逐个添加到列表中。该方法也不改变原列表的内存地址。
格式:
listname.extend(obj)
1. listname:要添加元素的列表
2. obj :要添加的数据,它可以是单个元素,也可以是列表、元组等
例如:
listname = [1,2,3]
listname.extend( 7 )
listname.extend( [7,8] )
listname = [1,2,3,7]
listname = [1,2,3,7,8]
·列表添加元素
4)使用【insert】方法
在当前列表的指定位置插入元素。它会把添加的元素为一个整体插入到列表中。
该方法也不改变原列表的内存地址。
格式:
listname.insert(index, obj)
1. listname:要添加元素的列表
2. index:指定位置的索引值
3. obj :要添加的数据,它可以是单个元素,也可以是列表、元组等
例如:listname = [1,2,3]
listname.insert( 1, 7 )
listname.insert( 1, [7,8] )
listname = [1,7,2,3]
listname = [1,[7,8],2,3]
数组元素的插入
(1)一维数组
操作 运行结果
a.append(100)
a.append(b)
a.extend(b)
对于数组a=[3,2,3,1,2],b=[123,456]
[3, 2, 3, 1, 2,100]
[3, 2, 3, 1, 2, [123, 456]]
[3, 2, 3, 1, 2, 123, 456]
35
数组元素的删除
data1 data2 data3 data4 data5
a
pos
n-1
思想:
当需要在数组中某个位置中删除一个元素时,只需将所有元素依次前移一位,然后将所有数组长度减一即可。
36
·列表删除元素
·根据场景分类
1)根据目标元素所在位置的索引进行删除
1. 使用 del 关键字
格式:
del listname[ index ] #单个元素
del listname[ start : end ] #中间一段连续的元素
例如:
listname = [ 1, 2, 3, 4, 5, 6 ]
del listname[ 2 ]
del listname[ -1: -4 ]
listname = [ 1, 2, 4, 5, 6 ]
listname = [ 1, 2, 3 ]
·列表删除元素
·根据场景分类
1)根据目标元素所在位置的索引进行删除
2. 使用 pop( )方法
格式:
listname.pop( index )
index:索引值;如果不写 index 参数,默认会删除列表中的最后一个元素
例如:
listname = [ 1, 2, 3, 4, 5, 6 ]
listname.pop( 3 )
listname.pop( )
listname = [ 1, 2, 3, 5, 6 ]
listname = [ 1, 2, 3, 4, 5 ]
·列表删除元素
·根据场景分类
2)根据元素本身的值进行删除
使用 remove( )方法
该方法只会删除第一个和指定值相同的元素,而且必须保证该元素是存在的,
否则会引发 ValueError 错误。
格式:
listname.remove( )
例如:
listname = [ 1, 2, 1, 2, 1, 2 ]
listname.remove( 1 )
listname.remove( 3 )
listname = [ 2, 1, 2, 1, 2 ]
ValueError
在使用 remove() 删除元素时需提前判断该元素是否存在。
操作 运行结果
a.pop()
print(a)
a.pop(2)
a.remove(3)
del a[:]
del a
del a[2]
对于数组a=[3,2,3,1,2,11]
[3, 2, 3, 1, 2]
[3, 2, 1, 2, 11]
[2, 3, 1, 2, 11]
[]
删除a列表
[3, 2, 1, 2, 11]
数组元素的删除
40
1.已知有一维数组a,则下列两段代码的功能是?
求数组中所有正数元素的和
s=0
for i in range(n):
if a[i]>0:
s=s+a[i]
print(s)
c=0
for i in range(n):
if a[i]>0:
c=c+1
print(c)
求数组中所有正数元素的个数
数组的基本操作——拓展实践
2.已知有一维数组a,则下列两段代码中k的功能?
K表示数组中最大的元素
K表示数组中最大的元素的下标
k=a[0]
for i in range(1,n):
if a[i]>k:
k=a[i]
print(k)
k=0
for i in range(1,n):
if a[i]>a[k]:
k=i
print(k)
数组的基本操作——拓展实践
k=a[1]- a[0]
for i in range(2,n):
if a[i]- a[i-1]>k:
k= a[i]- a[i-1]
print(k)
1.已知有一维数组a,则下列两段代码的功能是?
求数组相邻元素差值的最大值。(即a[1]-a[0]、a[2]-a[1]......a[n]-a[n-1]中的最大值)
min=10000
for i in range(0,n-1):
if a[i]>key:
if a[i]<min:
min= a[i]
print(min)
数组中所有大于key的元素中的最小值。
数组的基本操作——拓展实践
(1)抽象与建模
用n表示有资格参加摇号的申请人总数,用序列luck存储编号,luck 0 ,luck 1 ,…,luck n–1 依次表示n个编号,其中的下标表示每个编号的位置,luck i 的初值为第i+1位申请人的编号。使用变量m表示最终的车牌发放数量,计数器c表示已抽中人数,每当随机抽出一个有效的下标位置(如k)时,计数器c加1,输出申请人的编号后将该下标位置(如luck k )的值设为空串(表示该编号已被抽取),用来判断其后抽取的编号是否重复。重复该过程直至计数器c的值变为m,摇号结束。
44
(2)设计算法
由于该问题中数据规模可以预估,在处理过程中其数据规模保持不变,并需要根据随机产生的编号读取和修改对应的值,所以用数组来存储所有申请人的编号,下标表示该编号的位置。算法分为两个步骤:
①根据申请人总数n,初始化数组luck,其数组下标代表位置,数组元素值为申请者编号(类型为字符串),并使用计数器c表示已抽中人数,初始化值为0。
②使用随机整数函数randint(a,b)随机产生一个位置k,若其作为数组下标对应的数组数据元素值为空串,则表示该编号已被抽取,该编号为重复号码,需要重新生成;否则,表示该编号为有效编号,计数器c加1,输出对应的数组元素并修改数组元素值为空串,表示该编号已被抽取。
③重复执行步骤②,直至计数器c变为m,程序结束。
45
46
·杨辉三角
THANK YOU
$