You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

处理用户关联费用场景的最佳数据结构是什么?

优化用户-费用关联数据结构的方案

你当前用两个哈希表的思路没问题,核心问题出在删除费用时的遍历逻辑——其实完全不需要遍历整个userList,利用现有数据里的关联关系就能做到高效删除,树结构反而没必要,哈希表本身就可以满足高效操作的需求。

核心优化思路

每个费用对象里已经存了userId,这就是关键的关联线索!删除费用时,直接通过这个userId定位到对应的用户,不用遍历所有用户:

具体删除步骤(基于原数据结构)

function deleteExpense(expId) {
  // 1. 拿到要删除的费用对象,O(1)查找
  const expense = expenseList[expId];
  if (!expense) return;

  const userId = expense.userId;
  // 2. 通过userId定位到对应用户,O(1)查找
  const user = userList[userId];
  if (!user) return;

  // 3. 从用户的expenseIds数组中移除该费用ID
  user.expenseIds = user.expenseIds.filter(id => id !== expId);
  // 或者用splice(需先找到索引)
  // const index = user.expenseIds.indexOf(expId);
  // if (index !== -1) user.expenseIds.splice(index, 1);

  // 4. 从expenseList中删除该费用,O(1)操作
  delete expenseList[expId];
}

进一步提升删除效率:用Set替代数组存储expenseIds

如果用户的费用数量较多,数组的filter或splice是O(n)操作(n为该用户的费用数),换成Set的话,删除操作是O(1),效率更高:

修改后的用户数据结构:

export const userList = {
  1:  {     
    userId:1,
    firstname:'Jonathan',
    lastname: 'Lee',
    expenseIds: new Set([10, 20, 30, 40])
  },
  2:  {     
    userId:2,
    firstname:'Todd',
    lastname: 'Don',
    expenseIds: new Set([50])
  }
};

对应的删除逻辑更简洁:

function deleteExpense(expId) {
  const expense = expenseList[expId];
  if (!expense) return;

  const user = userList[expense.userId];
  if (!user) return;

  // Set的delete是O(1)操作
  user.expenseIds.delete(expId);
  delete expenseList[expId];
}

额外优化:消除冗余数据

你当前的费用对象里存了fullname,这属于冗余数据——如果用户修改姓名,所有关联的费用都要同步修改。可以改成每次需要显示全名时,通过userId从userList中取firstname和lastname拼接,减少维护成本。

为什么不用树结构?

树结构(比如红黑树)的查找、插入、删除是O(logn),而哈希表的这些操作是O(1)(平均情况),对于你当前的需求(主要是单条数据的增删查),哈希表的效率更高,完全没必要引入树结构。

内容的提问来源于stack exchange,提问作者Jonathan Lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 12:57:57