文章目录
- 顺序表
- 基本顺序表
- 元素外置顺序表
- 一体式顺序表
- 分离式顺序表
- 顺序表操作
- 增加元素
- Python的列表添加元素
- 删除元素
- 对Python的列表删除的操作
线性表:一组有序的数据组成的序列!
线性表
顺序表
链表
将元素顺序地存放在一块连续的存储区里,元素间的顺序关系由它们的存储顺序自然表示。
将元素存放在通过链接构造起来的一系列存储块中。
顺序表
基本顺序表
元素外置顺序表
一体式顺序表
分离式顺序表
顺序表
基本顺序表
基本顺序表,我们寻找一个元素,只需知道这个顺序表的物理地址及其下标即可,其时间复杂度为O(1)。
当我们操作列表或者元组的时候之所以是从0开始,就是因为顺序表中的下标从0开始计数,如果从1开始,则会多一步计算步骤,降低程序性能。
在Python中列表和元组占用的存储单元大小都为8。
list_empty = list()
list1 = [1]
list2 = [1, 2]
tuple_empty = tuple()
tuple1 = (1,)
tuple2 = (1, 2)
print(type(list1), '列表初始占用字节:', sys.getsizeof(list_empty), end='')
print(',存入一个的数据占用:', sys.getsizeof(list1) - sys.getsizeof(list_empty), end='')
print(',存入两个的数据占用:', sys.getsizeof(list2) - sys.getsizeof(list_empty))
print(type(tuple1), '元组初始占用字节:', sys.getsizeof(tuple_empty), end='')
print(',存入一个的数据占用:', sys.getsizeof(tuple1) - sys.getsizeof(tuple_empty), end='')
print(',存入两个的数据占用:', sys.getsizeof(tuple2) - sys.getsizeof(tuple_empty))
- <class ‘list’> 列表初始占用字节: 56,存入一个的数据占用: 8,存入两个的数据占用: 16
- <class ‘tuple’> 元组初始占用字节: 40,存入一个的数据占用: 8,存入两个的数据占用: 16
元素外置顺序表
在基础顺序表中,要求元素占用内存大小必须一致,但如果我们存储的数据中占用的内存大小不同时,哪我们就无法在简单的根据下标就能取出数据。
# Python中int和str占用内存大小
int_empty = int()
int_data = 1
str_empty = str()
str_data = 'a'
print(type(int_empty), '整数型初始占用字节:', sys.getsizeof(int_empty), '整数型占用字节:', sys.getsizeof(int_data) - sys.getsizeof(int_empty))
# <class 'int'> 整数型初始占用字节: 24 整数型占用字节: 4
print(type(str_empty), '字符型初始占用字节:', sys.getsizeof(str_empty), '字符型占用字节:', sys.getsizeof(str_data) - sys.getsizeof(str_empty))
# <class 'str'> 字符型初始占用字节: 49 字符型占用字节: 1
假设我们在数据中既要存储整数型同时又要存储字符型,这时就要用的元素外置顺序表。
与基本顺序表不同,元素外置顺序表中存储的并不是我们存入的元素,而是元素所在的物理地址,元素物理地址占用的存储单元都为一致的,这也是为什么元组和列表中,不管存储什么,存储多大的数据,都只占据8个字节。
8字节==64bit,而64bit最大存储为64个二进制一,相当于十进制18446744073709551615
list_empty = list()
tuple_empty = tuple()
tup = (18446744073709551615, 18446744073709551616)
lis = [18446744073709551615, 18446744073709551616]
print(type(lis), sys.getsizeof(lis) - sys.getsizeof(list_empty)) # <class 'list'> 16
print(type(tup), sys.getsizeof(tup) - sys.getsizeof(tuple_empty)) # <class 'tuple'> 16
可以从输出结果看出列表和元组采用的都是元素外置顺序表
一体式顺序表
在之前创建空列表和元组是,可以看出即列表和元组为空,但内部也有数据,这是数据记录了它们的一些基本信息,比如说开辟的空间大小,使用量等。在一体式顺序表中,这些基本信息和我们存入的数据是放在一起的。
通常一体式能更快的读取到数据,但空间使用完后难以在开辟新的空间。如需对数据进行增删改等操作通常都需开辟新空。Python中的元组就类似于一体式顺序表,元组并不支持数据的增删改,一旦创建就不可改变。
分离式顺序表
分离式顺序表将数据分离,方便数据的增加以及删除,当数据发生改变时只需将数据所在地址改变,无需改变表的内存地址。
顺序表操作
顺序表是实现增加以及删除
增加元素
增加元素
末尾添加
中间插入
将元素添加到表末,直接将元素加入表中,时间复杂度O(1)
保序插入
在保证表中原有顺序的情况下插入,时间复杂度O(n)
非保序插入
直接替换需要插入的地方的原有元素,时间复杂度O(1)
Python的列表添加元素
==.append()==末尾添加,==insert()==保序插入
lis = list(range(100))
def fn1():
app_lis = [1, 2, 2, 1]
for i in lis:
app_lis.append(i)
def fn2():
ins_lis = [1, 2, 2, 1]
for i in lis:
ins_lis.insert(3, i)
app_time = timeit.timeit('fn1()', 'from __main__ import fn1' ,number=100000)
int_time = timeit.timeit('fn2()', 'from __main__ import fn2' ,number=100000)
print(app_time) # 0.4836497
print(int_time) # 0.7581473
# 小扩展,用切片以及extend方法来添加元素
def fn3():
ext_lis = [1, 2, 2, 1]
ext_lis.extend(lis)
def fn4():
sec_lis = [1, 2, 2, 1]
for i in lis:
sec_lis[len(sec_lis):] = [i]
ext_time = timeit.timeit('fn3()', 'from __main__ import fn3' ,number=100000)
sec_time = timeit.timeit('fn4()', 'from __main__ import fn4' ,number=100000)
print(ext_time) # 0.03227119999999983
print(sec_time) # 1.2793392
从中我们可以看出就算插入地方相同的情况下保序插入在运行时间上还是和末尾插入相差较大。
删除元素
删除元素
删除末尾元素
指定元素删除
将表末的元素删除,时间复杂度O(1)
保序删除
在保证表中原有顺序的情况下删除,时间复杂度O(n)
非保序删除
将需要删除的内容和表末内容替换,之后删除末尾元素,时间复杂度O(1)
对Python的列表删除的操作
==.remove()保序删除,.pop()==删除末尾元素
rem_lis = [1] * 500 + [2] * 500
pop_lis = [1] * 500 + [2] * 500
sec_lis = [1] * 500 + [2] * 500
def fn1():
while 2 in rem_lis:
rem_lis.remove(2)
def fn2():
while 2 in pop_lis:
pop_lis.pop()
def fn3():
while 2 in sec_lis:
del sec_lis[len(sec_lis) - 1]
rem_time = timeit.timeit('fn1()', 'from __main__ import fn1', number=1000)
pop_time = timeit.timeit('fn2()', 'from __main__ import fn2', number=1000)
sec_time = timeit.timeit('fn3()', 'from __main__ import fn3', number=1000)
print(rem_time) # 0.0096498
print(pop_time) # 0.006983400000000001
print(sec_time) # 0.0074404