Skip to content

Commit 755cf39

Browse files
committedMay 15, 2019
python 内置标准数据结构分析
1 parent ee25702 commit 755cf39

File tree

4 files changed

+157
-0
lines changed

4 files changed

+157
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
# Created by imoyao at 2019/5/15 11:04
4+
"""
5+
字典操作及性能测试
6+
"""
7+
import pathlib
8+
import sys
9+
import timeit
10+
11+
util_p = pathlib.Path('../..').resolve()
12+
sys.path.append(str(util_p))
13+
from util import utils
14+
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
`Python` 中第二个主要的数据结构是`dict``dict``list`的不同之处在于你需要通过一
2+
个键(`key`)来访问元素,而不是通过`index`
3+
过现在我们要说的重点是,`dict`条目的访问和赋值都是`O(1)`的时间复杂度。`dict`的另一个重要的操
4+
作是所谓的`in`。检查一个键是否存在于`dict`中也只需 `O(1)`的时间。
5+
6+
## `dict`内置操作的时间复杂度
7+
8+
| 操作 | 操作说明 | 时间复杂度 |
9+
| ---------------- | --------- | ---------- |
10+
| copy | 复制 | O(n) |
11+
| get(value) | 获取 | O(1) |
12+
| set(value) | 修改 | O(1) |
13+
| delete(value) | 删除 | O(1) |
14+
| item `in` dict_obj | `in`关键字 | O(1) |
15+
| iterration | 迭代 | O(n) |
16+
17+
18+
## 更多阅读
19+
20+
[TimeComplexity](https://wiki.python.org/moin/TimeComplexity)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
# Created by imoyao at 2019/5/15 11:04
4+
"""
5+
列表操作及性能测试
6+
"""
7+
import pathlib
8+
import sys
9+
import timeit
10+
11+
util_p = pathlib.Path('../..').resolve()
12+
sys.path.append(str(util_p))
13+
from util import utils
14+
15+
16+
@utils.show_time
17+
def list_plus(n):
18+
a_list = []
19+
for i in range(n):
20+
a_list += [i]
21+
return a_list
22+
23+
24+
@utils.show_time
25+
def list_append(n):
26+
a_list = []
27+
for i in range(n):
28+
a_list.append(i)
29+
return a_list
30+
31+
32+
@utils.show_time
33+
def list_expression(n):
34+
return [_ for _ in range(n)]
35+
36+
37+
# @utils.show_time
38+
def list_range(n):
39+
return list(range(n))
40+
41+
42+
if __name__ == '__main__':
43+
# t1 = timeit.Timer('list_plus(1000)', 'from __main__ import list_plus', )
44+
# print(f'{list_plus.__name__} takes {t1.timeit(number=1000)} ms.')
45+
#
46+
# t2 = timeit.Timer('list_append(1000)', 'from __main__ import list_append')
47+
# print(f'{list_append.__name__} takes {t1.timeit(number=1000)} ms.')
48+
#
49+
# t3 = timeit.Timer('list_expression(1000)', 'from __main__ import list_expression')
50+
# print(f'{list_expression.__name__} takes {t1.timeit(number=1000)} ms.')
51+
#
52+
# t4 = timeit.Timer('list_range(1000)', 'from __main__ import list_range')
53+
# print(f'{list_range.__name__} takes {t1.timeit(number=1000)} ms.')
54+
55+
# 上方为使用timeit模块的测试,下方为使用自写装饰器的测试
56+
57+
n = 1000000
58+
list_plus(n)
59+
list_append(n)
60+
list_expression(n)
61+
list_range(n)
62+
'''
63+
# 输出
64+
The function **list_plus** takes 0.47864699363708496 time.
65+
The function **list_append** takes 0.41912221908569336 time.
66+
The function **list_expression** takes 0.14060020446777344 time.
67+
The function **list_range** takes 0.06196928024291992 time.
68+
'''
69+
70+
# 两种不同方式pop()操作耗时对比
71+
72+
n = 10000
73+
x = list_range(n)
74+
p1 = timeit.Timer('x.pop()', 'from __main__ import x')
75+
print(f'list_pop_normal takes {p1.timeit(number=1000)} ms.')
76+
77+
p2 = timeit.Timer('x.pop(0)', 'from __main__ import x')
78+
print(f'list_pop_index takes {p2.timeit(number=1000)} ms.')
79+
'''
80+
对比两次,发现指定index时耗时会随着list的增大而增加
81+
n = 1000000
82+
list_pop_normal takes 0.0006615779711864889 ms.
83+
list_pop_index takes 1.150215208006557 ms.
84+
# n = 10000
85+
list_pop_normal takes 0.00041822699131444097 ms.
86+
list_pop_index takes 0.0079622509656474 ms.
87+
'''
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
`List`可能是我们在 `Python` 实际开发中最频繁的数据结构之一。
2+
3+
## `list`内置操作的时间复杂度
4+
5+
| 操作 | 操作说明 | 时间复杂度 |
6+
| -------------------- | -------------------------------------------- | ---------- |
7+
| index(value) | 查找list某个元素的索引 | O(1) |
8+
| a = index(value) | 索引赋值 | O(1) |
9+
| append(value) | 队尾添加 | O(1) |
10+
| pop() | 队尾删除 | O(1) |
11+
| pop(index) | 根据索引删除某个元素 | O(n) |
12+
| insert(index, value) | 根据索引插入某个元素 | O(n) |
13+
| iterration | 列表迭代 | O(n) |
14+
| item `in` List | 列表搜索(in关键字) | O(n) |
15+
| slice [x:y] | 切片, 获取x, y为O(1), 获取x,y 中间的值为O(k) | O(k) |
16+
| del slice [x:y] | 删除切片,删除切片后数据需要重新移动/合并 | O(n) |
17+
| reverse | 列表反转 | O(n) |
18+
| sort | 排序 | O(nlogn) |
19+
20+
`index``append`是两个常见操作,它们无论列表多大,操作花费的时间都相同。当
21+
一个操作的速度不因列表的大小发生变化时,其操作复杂度就是 `O(1)`
22+
23+
随着列表长度的增加,从列表末端删除元素的 `pop()` 操作时间保持稳定,而从列表
24+
开头删除元素的 `pop(x)` 操作则随着长度的增加而增加。参见[代码](./code_test.py)`list_test.py:67`
25+
26+
说明
27+
`pop` 操作每次从列表的最后一位删除元素时复杂度为 `O(1)`,而将列表的第一个元素或中间任意
28+
一个位置的元素删除时,复杂度则为 `O(n)`。这样迥然不同的结果是由 `Python` 对列表的执行方式造
29+
成的。在 `Python` 的执行过程中,当从列表的第一位删除一个元素,其后的每一位元素都将向前挪动
30+
一位。你可能觉得这种操作很愚蠢,但当你仔细看完上表会发现这种执行方式是为了让 `index` 索引
31+
操作的复杂度降为 `O(1)`。这种在运行时间上的权衡是 `Python` 设计者的良苦用心。
32+
33+
## 更多阅读
34+
35+
[Python 内存分析:list和array](https://www.cnblogs.com/hellcat/p/8795841.html)

0 commit comments

Comments
 (0)
Please sign in to comment.