큐와 덱 문서의 구현 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""11.큐와 덱: 덱으로 큐와 LRU를 만들고 문서의 주장을 확인한다."""
import random
import time
from collections import OrderedDict, deque
def lru_deque(k, requests):
cache, hits = deque(), []
for x in requests:
if x in cache:
cache.remove(x)
cache.append(x)
hits.append(True)
else:
hits.append(False)
if k == 0:
continue
if len(cache) == k:
cache.popleft()
cache.append(x)
return hits, list(cache)
def lru_ordered(k, requests):
cache, hits = OrderedDict(), []
for x in requests:
if x in cache:
cache.move_to_end(x)
hits.append(True)
else:
hits.append(False)
if k == 0:
continue
if len(cache) == k:
cache.popitem(last=False)
cache[x] = True
return hits, list(cache)
def check(cond, msg):
if not cond:
raise AssertionError(msg)
def main():
q, states, out = deque(), [], []
for op in ["A", "B", None, "C", None]:
if op is None:
out.append(q.popleft())
else:
q.append(op)
states.append("".join(q))
check(states == ["A", "AB", "B", "BC", "C"] and out == ["A", "B"], "예시 표")
d = deque([1, 2, 3])
d.appendleft(0)
d.append(4)
check(list(d) == [0, 1, 2, 3, 4] and d[0] == 0 and d[-1] == 4 and d[2] == 2, "넣기, 보기")
d.rotate(2)
check(list(d) == [3, 4, 0, 1, 2], "rotate")
m = deque(maxlen=2)
for x in [1, 2, 3]:
m.append(x)
check(list(m) == [2, 3], "maxlen")
z = deque(maxlen=0)
z.append(1)
check(len(z) == 0, "maxlen=0")
# C1
q = deque([1, 2, 3])
q.append(4); q.popleft(); q.appendleft(0); q.rotate(1)
check(list(q) == [4, 0, 2, 3], "C1")
# C3
check(lru_deque(2, list("ABAC"))[1] == ["A", "C"], "C3 LRU")
fifo = deque(maxlen=2)
for x in "ABAC":
if x not in fifo:
fifo.append(x)
check(sorted(fifo) == ["B", "C"], "C3 FIFO")
# 덱 LRU = OrderedDict LRU
rng = random.Random(11)
for _ in range(3000):
k = rng.randint(0, 4)
reqs = [rng.choice("ABCDEF") for _ in range(rng.randint(1, 20))]
check(lru_deque(k, reqs) == lru_ordered(k, reqs), (k, reqs))
# popleft vs pop(0)
n = 100_000
a = list(range(n))
t = time.perf_counter()
while a:
a.pop(0)
t_list = time.perf_counter() - t
b = deque(range(n))
t = time.perf_counter()
while b:
b.popleft()
t_deque = time.perf_counter() - t
print(f"list.pop(0) {t_list:.3f}초, deque.popleft {t_deque:.4f}초, {t_list / t_deque:.0f}배")
check(t_list > 10 * t_deque, "popleft가 훨씬 빨라야 한다")
print("ALL CHECKS PASSED")
if __name__ == "__main__":
main()