Skip to content

Commit 70a333e

Browse files
committed
Deployed f92a213 with MkDocs version: 1.0.4
1 parent 4a29677 commit 70a333e

File tree

6 files changed

+156
-27
lines changed

6 files changed

+156
-27
lines changed

03_链表/linked_list/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ <h1 id="_3">双链表</h1>
303303
<li>看似我们反过来遍历双链表了。反过来从哪里开始呢?我们只要让 root 的 prev 指向 tail 节点,不就串起来了吗?</li>
304304
<li>直接删除节点,当然如果给的是一个值,我们还是需要查找这个值在哪个节点? - 但是如果给了一个节点,我们把它拿掉,直接让它的前后节点互相指过去不就行了?哇欧,删除就是 O(1) 了,两步操作就行啦</li>
305305
</ul>
306-
<p>好,废话不多说,我们在视频里介绍怎么实现一个双链表 ADT。
306+
<p>好,废话不多说,我们在视频里介绍怎么实现一个双链表 ADT。你可以直接在本项目的 <code>docs/03_链表/double_link_list.py</code> 找到代码。
307307
最后让我们看下它的时间复杂度:(这里 CircularDoubleLinkedList 取大写字母缩写为 cdll)</p>
308308
<table>
309309
<thead>

03_链表/lru_cache.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
"""
2+
python3 only
3+
LRU cache
4+
"""
5+
from collections import OrderedDict
6+
from functools import wraps
7+
8+
9+
def fib(n):
10+
if n <= 1:
11+
return 1
12+
return f(n - 1) + f(n - 2) # 由于涉及到重复计算,这个递归函数在 n 大了以后会非常慢
13+
14+
15+
"""
16+
下边就来写一个缓存装饰器来优化它。传统方法是用个数组记录之前计算过的值,但是这种方式不够 Pythonic
17+
"""
18+
19+
20+
def cache(func):
21+
"""先引入一个简单的装饰器缓存,其实原理很简单,就是内部用一个字典缓存已经计算过的结果"""
22+
store = {}
23+
24+
@wraps(func)
25+
def _(n): # 这里函数没啥意义就随便用下划线命名了
26+
if n in store:
27+
return store[n]
28+
else:
29+
res = func(n)
30+
store[n] = res
31+
return res
32+
return _
33+
34+
35+
@cache
36+
def f(n):
37+
if n <= 1:
38+
return 1
39+
return f(n - 1) + f(n - 2)
40+
41+
42+
"""
43+
问题来了,假如空间有限怎么办,我们不可能一直向缓存塞东西,当缓存达到一定个数之后,我们需要一种策略踢出一些元素,
44+
用来给新的元素腾出空间。
45+
一般缓存失效策略有
46+
- LRU(Least-Recently-Used): 替换掉最近请求最少的对象,实际中使用最广。cpu缓存淘汰和虚拟内存效果好,web应用欠佳
47+
- LFU(Least-Frequently-Used): 缓存污染问题(一个先前流行的缓存对象会在缓存中驻留很长时间)
48+
- First in First out(FIFO)
49+
- Random Cache: 随机选一个删除
50+
51+
LRU 是常用的一个,比如 redis 就实现了这个策略,这里我们来模拟实现一个。
52+
要想实现一个 LRU,我们需要一种方式能够记录访问的顺序,并且每次访问之后我们要把最新使用到的元素放到最后(表示最新访问)。
53+
当容量满了以后,我们踢出最早访问的元素。假如用一个链表来表示的话:
54+
55+
[1] -> [2] -> [3]
56+
57+
假设最后边是最后访问的,当访问到一个元素以后,我们把它放到最后。当容量满了,我们踢出第一个元素就行了。
58+
一开始的想法可能是用一个链表来记录访问顺序,但是单链表有个问题就是如果访问了中间一个元素,我们需要拿掉它并且放到链表尾部。
59+
而单链表无法在O(1)的时间内删除一个节点(必须要先搜索到它),但是双端链表可以,因为一个节点记录了它的前后节点,
60+
只需要把要删除的节点的前后节点链接起来就行了。
61+
还有个问题是如何把删除后的节点放到链表尾部,如果是循环双端链表就可以啦,我们有个 root 节点链接了首位节点,
62+
只需要让 root 的前一个指向这个被删除节点,然后让之前的最后一个节点也指向它就行了。
63+
64+
使用了循环双端链表之后,我们的操作就都是 O(1) 的了。这也就是使用一个 dict 和一个 循环双端链表 实现LRU 的思路。
65+
不过一般我们使用内置的 OrderedDict(原理和这个类似)就好了,要实现一个循环双端链表是一个不简单的事情。
66+
67+
"""
68+
69+
70+
class LRUCache:
71+
def __init__(self, capacity=128):
72+
self.capacity = capacity
73+
# 借助 OrderedDict 我们可以快速实现一个 LRUCache,OrderedDict 内部其实也是使用循环双端链表实现的
74+
# OrderedDict 有两个重要的函数用来实现 LRU,一个是 move_to_end,一个是 popitem,请自己看文档
75+
self.od = OrderedDict()
76+
77+
def get(self, key, default=None):
78+
val = self.od.get(key, default) # 如果没有返回 default,保持 dict 语义
79+
self.od.move_to_end(key) # 每次访问就把key 放到最后表示最新访问
80+
return val
81+
82+
def add_or_update(self, key, value):
83+
if key in self.od: # update
84+
self.od[key] = value
85+
self.od.move_to_end(key)
86+
else: # insert
87+
self.od[key] = value
88+
if len(self.od) > self.capacity: # full
89+
self.od.popitem(last=False)
90+
91+
def __call__(self, func):
92+
"""
93+
一个简单的 LRU 实现。有一些问题需要思考下:
94+
95+
- 这里为了简化默认参数只有一个数字 n,假如可以传入多个参数,如何确定缓存的key 呢?
96+
- 这里实现没有考虑线程安全的问题,要如何才能实现线程安全的 LRU 呢?当然如果不是多线程环境下使用是不需要考虑的
97+
- 假如这里没有用内置的 dict,你能使用 redis 来实现这个 LRU 吗,如果使用了 redis,我们可以存储更多数据到服务器。而使用字典实际上是换到到了Python进程里(localCache)。
98+
"""
99+
def _(n):
100+
if n in self.od:
101+
return self.get(n)
102+
else:
103+
val = func(n)
104+
self.add_or_update(n, val)
105+
return val
106+
return _
107+
108+
109+
@LRUCache(10)
110+
def f_use_lru(n):
111+
if n <= 1:
112+
return 1
113+
return f(n - 1) + f(n - 2)
114+
115+
116+
def test():
117+
import time
118+
beg = time.time()
119+
for i in range(34):
120+
print(f(i))
121+
print(time.time() - beg)
122+
beg = time.time()
123+
for i in range(34):
124+
print(f_use_lru(i))
125+
print(time.time() - beg)
126+
127+
128+
if __name__ == '__main__':
129+
test()

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,5 +528,5 @@ <h2 id="_20">本电子书制作和写作方式</h2>
528528

529529
<!--
530530
MkDocs version : 1.0.4
531-
Build Date UTC : 2018-12-21 01:26:47
531+
Build Date UTC : 2018-12-22 02:52:07
532532
-->

search/search_index.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

sitemap.xml

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,122 +2,122 @@
22
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
33
<url>
44
<loc>None</loc>
5-
<lastmod>2018-12-21</lastmod>
5+
<lastmod>2018-12-22</lastmod>
66
<changefreq>daily</changefreq>
77
</url>
88
<url>
99
<loc>None</loc>
10-
<lastmod>2018-12-21</lastmod>
10+
<lastmod>2018-12-22</lastmod>
1111
<changefreq>daily</changefreq>
1212
</url>
1313
<url>
1414
<loc>None</loc>
15-
<lastmod>2018-12-21</lastmod>
15+
<lastmod>2018-12-22</lastmod>
1616
<changefreq>daily</changefreq>
1717
</url>
1818
<url>
1919
<loc>None</loc>
20-
<lastmod>2018-12-21</lastmod>
20+
<lastmod>2018-12-22</lastmod>
2121
<changefreq>daily</changefreq>
2222
</url>
2323
<url>
2424
<loc>None</loc>
25-
<lastmod>2018-12-21</lastmod>
25+
<lastmod>2018-12-22</lastmod>
2626
<changefreq>daily</changefreq>
2727
</url>
2828
<url>
2929
<loc>None</loc>
30-
<lastmod>2018-12-21</lastmod>
30+
<lastmod>2018-12-22</lastmod>
3131
<changefreq>daily</changefreq>
3232
</url>
3333
<url>
3434
<loc>None</loc>
35-
<lastmod>2018-12-21</lastmod>
35+
<lastmod>2018-12-22</lastmod>
3636
<changefreq>daily</changefreq>
3737
</url>
3838
<url>
3939
<loc>None</loc>
40-
<lastmod>2018-12-21</lastmod>
40+
<lastmod>2018-12-22</lastmod>
4141
<changefreq>daily</changefreq>
4242
</url>
4343
<url>
4444
<loc>None</loc>
45-
<lastmod>2018-12-21</lastmod>
45+
<lastmod>2018-12-22</lastmod>
4646
<changefreq>daily</changefreq>
4747
</url>
4848
<url>
4949
<loc>None</loc>
50-
<lastmod>2018-12-21</lastmod>
50+
<lastmod>2018-12-22</lastmod>
5151
<changefreq>daily</changefreq>
5252
</url>
5353
<url>
5454
<loc>None</loc>
55-
<lastmod>2018-12-21</lastmod>
55+
<lastmod>2018-12-22</lastmod>
5656
<changefreq>daily</changefreq>
5757
</url>
5858
<url>
5959
<loc>None</loc>
60-
<lastmod>2018-12-21</lastmod>
60+
<lastmod>2018-12-22</lastmod>
6161
<changefreq>daily</changefreq>
6262
</url>
6363
<url>
6464
<loc>None</loc>
65-
<lastmod>2018-12-21</lastmod>
65+
<lastmod>2018-12-22</lastmod>
6666
<changefreq>daily</changefreq>
6767
</url>
6868
<url>
6969
<loc>None</loc>
70-
<lastmod>2018-12-21</lastmod>
70+
<lastmod>2018-12-22</lastmod>
7171
<changefreq>daily</changefreq>
7272
</url>
7373
<url>
7474
<loc>None</loc>
75-
<lastmod>2018-12-21</lastmod>
75+
<lastmod>2018-12-22</lastmod>
7676
<changefreq>daily</changefreq>
7777
</url>
7878
<url>
7979
<loc>None</loc>
80-
<lastmod>2018-12-21</lastmod>
80+
<lastmod>2018-12-22</lastmod>
8181
<changefreq>daily</changefreq>
8282
</url>
8383
<url>
8484
<loc>None</loc>
85-
<lastmod>2018-12-21</lastmod>
85+
<lastmod>2018-12-22</lastmod>
8686
<changefreq>daily</changefreq>
8787
</url>
8888
<url>
8989
<loc>None</loc>
90-
<lastmod>2018-12-21</lastmod>
90+
<lastmod>2018-12-22</lastmod>
9191
<changefreq>daily</changefreq>
9292
</url>
9393
<url>
9494
<loc>None</loc>
95-
<lastmod>2018-12-21</lastmod>
95+
<lastmod>2018-12-22</lastmod>
9696
<changefreq>daily</changefreq>
9797
</url>
9898
<url>
9999
<loc>None</loc>
100-
<lastmod>2018-12-21</lastmod>
100+
<lastmod>2018-12-22</lastmod>
101101
<changefreq>daily</changefreq>
102102
</url>
103103
<url>
104104
<loc>None</loc>
105-
<lastmod>2018-12-21</lastmod>
105+
<lastmod>2018-12-22</lastmod>
106106
<changefreq>daily</changefreq>
107107
</url>
108108
<url>
109109
<loc>None</loc>
110-
<lastmod>2018-12-21</lastmod>
110+
<lastmod>2018-12-22</lastmod>
111111
<changefreq>daily</changefreq>
112112
</url>
113113
<url>
114114
<loc>None</loc>
115-
<lastmod>2018-12-21</lastmod>
115+
<lastmod>2018-12-22</lastmod>
116116
<changefreq>daily</changefreq>
117117
</url>
118118
<url>
119119
<loc>None</loc>
120-
<lastmod>2018-12-21</lastmod>
120+
<lastmod>2018-12-22</lastmod>
121121
<changefreq>daily</changefreq>
122122
</url>
123123
</urlset>

sitemap.xml.gz

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)