
1) 【一句话结论】采用基于堆的优先队列,结合订单ID到堆位置的哈希表映射,支持时间优先(时间戳升序)和价格优先(买入价高、卖出价低优先),插入/删除及撤销操作时间复杂度均为O(log n),空间复杂度O(n),适用于高并发期货撮合引擎。
2) 【原理/概念讲解】解释订单类型与优先级规则:订单分为买入(Buy)和卖出(Sell),价格优先规则为买入按“价格越高(买方出价越高)优先”,卖出按“价格越低(卖方要价越低)优先”;时间优先规则统一为“时间戳升序,最早到先处理”。使用堆(完全二叉树,满足堆序性),插入新订单时通过“上浮”(最大堆/最小堆)调整位置,删除堆顶时替换堆顶元素并“下沉”调整,保证操作时间复杂度O(log n)。为支持撤销操作,维护一个哈希表(订单ID→堆位置),撤销时通过ID快速定位订单,用无效值替换堆顶元素并调整堆,避免遍历整个堆。类比:急救中心任务队列,紧急任务(时间早或优先级高)先处理,堆自动排序,插入后自动调整位置,撤销时直接替换堆顶,不影响其他订单。
3) 【对比与适用场景】
| 数据结构 | 定义 | 插入/删除时间复杂度 | 空间复杂度 | 适用场景 | 注意点 |
|---|---|---|---|---|---|
| 数组排序(快排) | 顺序存储,排序后有序 | O(n log n) | O(1)(原地) | 低并发,静态数据 | 不支持动态插入删除,撤销操作需重新排序 |
| 平衡二叉搜索树(红黑树) | 自平衡树,支持动态插入删除 | O(log n) | O(n) | 需频繁插入删除,有序访问 | 高并发下响应时间可能比堆慢,因旋转操作 |
| 堆(带ID映射表) | 完全二叉树+哈希表(ID→位置) | 插入/删除O(log n),撤销O(log n) | O(n) | 高并发订单撮合,优先级排序 | 撤销通过堆顶替换+调整实现高效删除,需维护哈希表 |
| 跳表(无锁) | 分层链表,支持动态插入删除 | 插入/删除O(log n),撤销O(log n) | O(n) | 极高并发,无锁场景 | 需额外内存,实现复杂 |
4) 【示例】
订单示例及撤销操作伪代码:
class OrderBook:
def __init__(self):
self.bids = MaxHeap() # 买入(价格高优先)
self.asks = MinHeap() # 卖出(价格低优先)
self.time_queue = MinHeap() # 时间优先,按时间戳升序
self.id_to_pos = {} # 订单ID到堆位置的映射
def add_order(self, order_type, price, time, qty, order_id):
order = (price, time, qty, order_id)
if order_type == "buy":
self.bids.push((price, time, order))
self.time_queue.push((time, order))
else:
self.asks.push((price, time, order))
self.time_queue.push((time, order))
self.id_to_pos[order_id] = (self.time_queue.size() - 1, self.bids.size() - 1 if order_type == "buy" else self.asks.size() - 1)
def cancel_order(self, order_id, cancel_time):
pos, bid_pos = self.id_to_pos.get(order_id)
if pos is not None:
self.time_queue.replace_top((cancel_time, None)) # 替换为无效值
self.time_queue.sift_down(0)
if bid_pos != -1:
self.bids.replace_top((float('-inf'), None)) # 买入用最大堆
self.bids.sift_down(0)
else:
self.asks.replace_top((float('inf'), None)) # 卖出用最小堆
self.asks.sift_down(0)
del self.id_to_pos[order_id]
def match(self):
while not self.bids.empty() and not self.asks.empty():
bid_price, _, bid = self.bids.top()
ask_price, _, ask = self.asks.top()
if bid_price >= ask_price:
self.bids.pop()
self.asks.pop()
5) 【面试口播版答案】
面试官您好,设计期货订单排序算法时,核心是用堆结构结合订单ID映射表。具体来说,订单分为买入和卖出,价格优先规则是买入按价格高优先、卖出按价格低优先,时间优先按时间戳升序。用最大堆处理买入订单(价格高优先),最小堆处理卖出订单(价格低优先),同时维护一个时间队列(最小堆,时间早先处理)。为了支持撤销操作,我们维护一个哈希表,记录每个订单ID在时间队列和价格队列中的位置。当撤销订单时,通过ID快速定位,用无效值替换堆顶元素并调整堆,这样撤销操作的时间复杂度也是O(log n)。插入新订单时,先按时间戳插入时间队列,再根据类型插入价格队列,撮合时从价格队列取出最高买入价和最低卖出价匹配,成交后更新剩余订单。这种设计能高效处理高并发订单,满足时间优先和价格优先的规则。
6) 【追问清单】
7) 【常见坑/雷区】