3. 数组和列表

先说基本的线性结构,常用的就是线性结构,也是比较简单的,特点如下:

内存连续,一开始就会分配一块固定的内存给它,可以通过下标去快速访问常用的数组和列表。


在python 里面有array和list两种

Array:

python中array用到的机会没有list多,

先演示一下array的用法(https://docs.python.org/2/library/array.html):

from array import array

arr = array('u', 'abcdefg')
print (arr[0])
print (arr[3])
print (arr[5])

结果:

a

d

f

缺点也比较明显:

(1)只能存同一种类型,不想list可以在不同下标存不同类型的元素;

(2)只能存一些比较基本的数值、字符类型,用得不是很多,一般用numpy里面的array,来做一些数值的处理。


List:

list也是一个线性结构

(1)list的工作过程

通过C解释器代码可以看到是按照 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ....的顺序增长的

https://github.com/python/cpython/blob/master/Objects/listobject.c

image.png


append:


操作 内存分配策略 平均时间复杂度
init[] *  pylistobj O(1)
append(0)

image.png
append(0)会分配4个pylistobj,不会一次只分配一个,会占用空间

当分配足够的空间,时间复杂度是O(1),否则它就会重新开辟并拷贝原来的数据到新开辟的空间中去,这时就会退化,时间复杂度是O(n)
append(1) image.png
append(2) image.png
append(3)

image.png

append(4)

image.png当超出它的大小限制的时候,会进行一个resize的操作,因为不够装了,所以重新分配8个空间

























insert:

insert

insert 一般会往中间插入,这样会比较耗费时间,会重新进行内存分配,比如insert一个元素 -1,这时就要重新开辟空间,总长度就变成了16

image.png
数组的容量称为capacity(总内存分配的容量),而length指的是有多少个元素,比如之前append了5个元素,insert一个-1,这时length就是6,即6个元素,而capacity是16,所以insert操作会重新的去分配,所以他的时间复杂度平均下来是O(n)

O(n)


pop:

pop

pop默认是移除最后一个元素,所以时间复杂度是O(1)

image.png
因为只是要把第5位指针往前面移动一位,这时length的长度变成5个,时间复杂度O(1);

但如果从中间进行pop的时候,这样就会把后面的元素往前移,这时候时间复杂度就会退化,变成O(n).

O(1)

O(n)


remove:

remove

image.png
加入要把中间的元素删除掉,要把后面的每一个元素全都往前移,这时候的时间复杂度是O(n)

O(n)


如图:

操作 平均时间复杂度
list[index] O(1)
list.append O(1)
list.insert O(n)
list.pop(index), default last element O(1)
list.remove O(n)


所以在用list的时候,频繁的进行insert/remove的时候,或是在中间进行pop的话,

可能list就不是一个合适的数据结构,要选用其他更高效的数据结构。


练习:用list实现array的ADT

实现一个定长的数组array的ADT

ps:在其他一些语言中,内置的数组结构就是定长的。














猜你喜欢

转载自blog.51cto.com/286577399/2148991