📅  最后修改于: 2023-12-03 14:58:31.370000             🧑  作者: Mango
本题是一道算法题,要求实现一个门控系统来控制进出门的权限并记录每个人的进出情况。这可以在许多实际场景中应用,如办公区门禁系统、学生宿舍门禁系统等。
门控系统需要支持以下三个功能:
门控系统应当支持并发使用,并能够正确地处理并发读写请求。
该门控系统最主要的数据结构是一个哈希表,键为卡编号,值为该卡对应的人的ID号码和一张进出记录表。
进出记录表是一个有序的双向链表,每个节点包含进出状态(入门或出门)、时间戳和相应的卡编号和人ID号码。为了实现快速查询,记录表按时间戳从早到晚排序。同时,在每个人的记录表中维护两个指针,一个指向最早的进门记录节点,另一个指向最近的出门记录节点。这样,在查询某个人最近的进出记录时,只需要从最近的出门记录节点开始向前遍历链表,直到遇到最近的进门记录。
系统中涉及到的所有操作(注册、注销、进出门、查询记录)都需要加锁实现并发使用。锁可以粗粒度到整个门禁系统,也可以细粒度到每个单一卡的记录表。
门控系统在注册卡、注销卡和进出门时需要进行哈希表的读写操作,时间复杂度为O(1)。查询某个人最近的进出记录时需要遍历链表,时间复杂度为O(k),其中k为该人在系统中的进出次数。由于链表按时间戳排序,因此在大多数情况下k不会很大,因此查询的时间复杂度也可以被视为O(1)。
class GateSystem:
def __init__(self):
self.cards = {}
self.lock = Lock()
def register_card(self, card_id, person_id):
with self.lock:
if card_id in self.cards:
raise ValueError('Card id already registered')
self.cards[card_id] = {'person_id': person_id, 'records': LinkedList()}
def unregister_card(self, card_id):
with self.lock:
if card_id not in self.cards:
raise ValueError('Card id not registered')
del self.cards[card_id]
def enter(self, card_id):
with self.lock:
if card_id not in self.cards:
raise ValueError('Card id not registered')
card = self.cards[card_id]
card['records'].add('in', time.time(), card_id, card['person_id'])
def exit(self, card_id):
with self.lock:
if card_id not in self.cards:
raise ValueError('Card id not registered')
card = self.cards[card_id]
card['records'].add('out', time.time(), card_id, card['person_id'])
def get_records(self, person_id, time_span):
with self.lock:
records = []
if person_id is None:
for card in self.cards.values():
records.extend(card['records'].get_records(time_span))
else:
for card in self.cards.values():
if card['person_id'] == person_id:
records.extend(card['records'].get_records(time_span))
return records
class LinkedList:
class Node:
def __init__(self, action, timestamp, card_id, person_id):
self.action = action
self.timestamp = timestamp
self.card_id = card_id
self.person_id = person_id
self.next = None
self.prev = None
def __init__(self):
self.head = None
self.tail = None
def add(self, action, timestamp, card_id, person_id):
node = self.Node(action, timestamp, card_id, person_id)
if self.head is None:
self.head = self.tail = node
else:
node.prev = self.tail
self.tail.next = node
self.tail = node
def get_records(self, time_span):
records = []
node = self.tail
while node:
if time.time() - node.timestamp > time_span:
break
records.append((node.timestamp, node.person_id, node.card_id, node.action))
node = node.prev
return records
以上是一个简单的Python实现,使用了线程锁保证并发安全。哈希表使用Python自带的字典实现,链表使用自定义的双向链表实现。为了简单起见,在记录表中保存了时间戳而非日期,同时默认使用time.time()获取当前时间戳。