计数器加三次
下面这段给同一个计数器加了三次。打出每次加完之后的值(三段,用 / 隔开)。
题面里已经写好一个**迷你 Redis**(class Mini)和一个当数据库用的 Store
Mini 的时间是**步数**:r.tick(n) 表示过了 n 秒(过期由它触发)
字符串 set(k, v, ex=秒) / get(k) / incr(k) / delete(k) / exists(k) / ttl(k)
结构 hset,hget,hlen / rpush,lrange,llen / sadd,scard
排行榜 zadd(k, 名字, 分) / zincrby / zscore / zcard
zrevrange(k, a, b) 分高的在前|zrevrank(k, 名字) 名次从 0 起
淘汰 Mini(maxsize=n) 超过 n 个键就淘汰**最久没碰过**的,记在 r.evicted 里
Store s.query(key) 取一行,**每取一次 s.reads 就加一**(用来数回源次数)
里面只有 u1~u5 五个用户class Mini:
"""一个够用的迷你 Redis。时间用**步数**走:tick(n) 表示过了 n 秒。"""
def __init__(self, maxsize=0):
self.d = {} # 键 → 值
self.exp = {} # 键 → 到点的时刻(没设过期的不在这里)
self.used = {} # 键 → 最后一次被碰是第几回(淘汰要用)
self.seq = 0 # 只增不减:每碰一次 +1
# ⚠️ 不能用 now —— 读一下并不会让时间前进
self.now = 0
self.maxsize = maxsize # 0 表示不限;超了就淘汰最久没碰的那个
self.evicted = [] # 被淘汰掉的键,按先后记下来
# ── 时间 ──────────────────────────────────────────────────────────
def tick(self, n=1):
self.now = self.now + n
for k in list(self.exp):
if self.exp[k] <= self.now:
self.d.pop(k, None)
self.exp.pop(k, None)
self.used.pop(k, None)
def _touch(self, k):
self.seq = self.seq + 1
self.used[k] = self.seq
def _evict(self):
while self.maxsize and len(self.d) > self.maxsize:
old = min(self.used, key=lambda k: (self.used[k], k))
self.d.pop(old, None)
self.exp.pop(old, None)
self.used.pop(old, None)
self.evicted.append(old)
# ── 字符串 ────────────────────────────────────────────────────────
def set(self, k, v, ex=None):
self.d[k] = v
self.exp.pop(k, None)
if ex is not None:
self.exp[k] = self.now + ex
self._touch(k)
self._evict()
def get(self, k):
if k not in self.d:
return None
self._touch(k)
return self.d[k]
def incr(self, k):
self.d[k] = int(self.d.get(k, 0)) + 1
self._touch(k)
self._evict()
return self.d[k]
def delete(self, k):
self.d.pop(k, None)
self.exp.pop(k, None)
self.used.pop(k, None)
def exists(self, k):
return k in self.d
def ttl(self, k):
"""还能活几秒。没设过期返回 -1,键都不在返回 -2(和 Redis 一样)。"""
if k not in self.d:
return -2
if k not in self.exp:
return -1
return self.exp[k] - self.now
def dbsize(self):
return len(self.d)
# ── 哈希 / 列表 / 集合 ────────────────────────────────────────────
def hset(self, k, f, v):
self.d.setdefault(k, {})[f] = v
self._touch(k)
self._evict()
def hget(self, k, f):
self._touch(k)
return self.d.get(k, {}).get(f)
def hlen(self, k):
return len(self.d.get(k, {}))
def rpush(self, k, v):
self.d.setdefault(k, []).append(v)
self._touch(k)
self._evict()
def lrange(self, k, a, b):
self._touch(k)
return self.d.get(k, [])[a:b + 1] if b >= 0 else self.d.get(k, [])[a:]
def llen(self, k):
return len(self.d.get(k, []))
def sadd(self, k, v):
self.d.setdefault(k, set()).add(v)
self._touch(k)
self._evict()
def scard(self, k):
return len(self.d.get(k, set()))
# ── 有序集合(排行榜用)──────────────────────────────────────────
def zadd(self, k, member, score):
self.d.setdefault(k, {})[member] = score
self._touch(k)
self._evict()
def zincrby(self, k, member, delta):
z = self.d.setdefault(k, {})
z[member] = z.get(member, 0) + delta
self._touch(k)
return z[member]
def zscore(self, k, member):
return self.d.get(k, {}).get(member)
def zcard(self, k):
return len(self.d.get(k, {}))
def _sorted(self, k):
"""分高的在前;分一样的按名字排,保证每次结果一模一样。"""
z = self.d.get(k, {})
return sorted(z, key=lambda m: (-z[m], m))
def zrevrange(self, k, a, b):
return self._sorted(k)[a:b + 1]
def zrevrank(self, k, member):
"""从 0 开始的名次,不在里面返回 None。"""
order = self._sorted(k)
return order.index(member) if member in order else None
# ── 一个"慢的那份":每读一次就记一笔,用来数回源次数 ──────────────────
class Store:
"""当作数据库用。里面只有 u1~u5 这几个用户。"""
def __init__(self):
self.reads = 0
self.rows = {"u1": "甲", "u2": "乙", "u3": "丙", "u4": "丁", "u5": "戊"}
def query(self, key):
self.reads = self.reads + 1
return self.rows.get(key)
r = Mini()
a = r.incr("pv")
b = r.incr("pv")
c = r.incr("pv")
print(str(a) + "/" + str(b) + "/" + str(c))
全部评论