动态key排序查询应选什么数据结构?图书存量变动时如何实现动态排序?
解决方案
核心选型说明
你需要的是支持自动排序、可处理重复quantity值、变更后可自动重排的映射结构,Java原生容器中TreeMap是最匹配的实现,只需要额外解决两个问题:1、quantity重复导致的key冲突;2、quantity变更后触发重排的逻辑。
步骤1:定义可排序的组合Key解决重复值问题
因为不同图书的quantity可能重复,无法直接作为TreeMap的Key(重复Key会触发值覆盖),我们将唯一的图书id和quantity组合为自定义Key,排序规则优先按quantity排序,quantity相同时按id排序,保证Key全局唯一:
// JDK16及以上版本可直接用record,低版本替换为普通类重写equals、hashCode、compareTo方法即可 public record BookSortKey(Long quantity, Long bookId) implements Comparable<BookSortKey> { @Override public int compareTo(BookSortKey other) { // 此处按quantity倒序排序,如需正序将Long.compare的两个参数互换即可 int quantityCompareRes = Long.compare(other.quantity, this.quantity); if (quantityCompareRes != 0) { return quantityCompareRes; } // quantity相同时按id排序,确保Key不会重复 return Long.compare(this.bookId, other.bookId); } }
步骤2:封装更新逻辑实现自动重排
TreeMap本身不会监听Key的属性变化,因此我们封装容器操作,在quantity更新时自动执行「删除旧Entry-插入新Entry」逻辑,上层调用无需感知排序细节:
首先给原Book类补充getter、setter方法:
public class Book { private Long id; private Long quantity; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Long getQuantity() { return quantity; } public void setQuantity(Long quantity) { this.quantity = quantity; } }
封装排序容器:
import java.util.ArrayList; import java.util.List; import java.util.TreeMap; public class SortedBookManager { // 底层用TreeMap存储,插入时自动按Key规则排序 private final TreeMap<BookSortKey, Book> sortedBookMap = new TreeMap<>(); // 新增图书 public void addBook(Book book) { sortedBookMap.put(new BookSortKey(book.getQuantity(), book.getId()), book); } // 更新图书库存,自动触发重排 public void updateQuantity(Long bookId, Long newQuantity) { // 查找目标图书 Book target = sortedBookMap.values().stream() .filter(book -> book.getId().equals(bookId)) .findFirst() .orElseThrow(() -> new IllegalArgumentException("不存在ID为" + bookId + "的图书")); // 先删除旧的Entry sortedBookMap.remove(new BookSortKey(target.getQuantity(), bookId)); // 更新库存 target.setQuantity(newQuantity); // 插入新Entry,TreeMap会自动将其放到正确的排序位置 sortedBookMap.put(new BookSortKey(newQuantity, bookId), target); } // 获取已排序的图书列表,直接按顺序遍历即可 public List<Book> getSortedBooks() { return new ArrayList<>(sortedBookMap.values()); } }
注意事项
- 不要直接修改
Book实例的quantity字段,必须通过updateQuantity方法执行更新,否则会出现排序错乱 - 单次更新的时间复杂度为
O(logn),高频更新场景下性能远高于每次全量排序List的方案 - 多线程并发场景下,可将
TreeMap替换为线程安全的ConcurrentSkipListMap,或者给更新方法加锁保证线程安全
内容的提问来源于stack exchange,提问作者Jimmy Guo
相关产品推荐
相关产品推荐

