一、核心结论(先记住这 10 条)
- 默认排序用稳定算法 :List.sort / Collections.sort / Kotlin list.sortWith {} → 底层 TimSort(稳定,适合多字段排序与 UI 列表)。
 - 数字比较不要相减:用 Integer.compare(a,b) / Comparator.comparingInt(::field),避免溢出与符号错误。
 - 字符串排序面向用户要用 Collator(按语言/Locale 排序),不要用简单 String.compareTo;中英文混排或阿语等尤其明显。
 - Null 安全:用 Comparator.nullsFirst/Last 或 Kotlin nullsFirst/Last() 包装比较器。
 - 多字段排序:用链式比较器(thenComparing / thenBy),稳定排序可保留同一主键下的原相对顺序。
 - 频繁"判断是否包含" :不要每次 list.contains()(O(n)),改用 HashSet/HashMap 预建索引(O(1))。
 - 二分查找只适用于已排序区间 :Collections.binarySearch / Kotlin binarySearch,找不到时返回"插入点编码值",要解码 idx = -pos - 1。
 - 重复按同一 key 排序:先"装饰-排序-去装饰"(Schwartzian transform)或缓存 key,减少重复计算。
 - 大规模实时增删 :不要反复全量排序;用二分插入维持有序,或改 TreeSet/PriorityQueue/数据库排序。
 - RecyclerView 变更:排序后用 DiffUtil 计算差异,避免整表闪烁和 O(n) 级刷新。
 
二、排序(Sorting)
1) 常用 API 与稳定性
- 
Java
- list.sort(cmp)(JDK8+)/Collections.sort(list, cmp) → TimSort,稳定,O(n log n),局部有序时更快。
 - Arrays.sort(Object[]) → 稳定;Arrays.sort(int[])(原生类型)→ 双轴快速排序,不稳定。
 
 - 
Kotlin
- 
就地:mutableList.sort() / sortBy { } / sortWith(cmp)(稳定)。
 - 
返回新列表:sorted()/sortedBy/with(拷贝后排序,适合不可变 Pipeline)。
 
 - 
 
2) 多字段排序(链式比较器)
Java
            
            
              scss
              
              
            
          
          Comparator<User> cmp = Comparator
  .comparing(User::getVip).reversed()          // VIP 优先
  .thenComparingInt(User::getLevel).reversed() // 等级高在前
  .thenComparing(User::getName, Collator.getInstance(Locale.CHINA)); // 中文名
users.sort(cmp);
        Kotlin
            
            
              css
              
              
            
          
          users.sortWith(
  compareByDescending<User> { it.vip }
    .thenByDescending { it.level }
    .thenComparator { a, b -> Collator.getInstance(Locale.CHINA).compare(a.name, b.name) }
)
        3) Null 与倒序
            
            
              less
              
              
            
          
          Comparator<Foo> cmp = Comparator
  .comparing(Foo::getScore, Comparator.nullsLast(Integer::compare))
  .reversed(); // 全局倒序
        Kotlin:nullsLast(naturalOrder()) / reversed()。
4) 字符串的"语言学排序"
用户可见文本排序用:
            
            
              ini
              
              
            
          
          Collator collator = Collator.getInstance(locale); // e.g. Locale.SIMPLIFIED_CHINESE / ARABIC
list.sort(Comparator.comparing(Item::getTitle, collator));
        需要忽略大小写/重音:配置 collator.setStrength(Collator.PRIMARY)。
5) 性能与内存
- TimSort 适合"部分有序" :滚动列表、分页合并、时间线排序性能更佳。
 - 装饰-排序-去装饰(Key 缓存) :避免在比较器里反复计算昂贵 key。
 
            
            
              kotlin
              
              
            
          
          data class Decor<T>(val key: Int, val v: T)
val decorated = items.map { Decor(calcExpensiveKey(it), it) }
decorated.sortBy { it.key }
val sorted = decorated.map { it.v }
        6) 大列表与并行
- Server/JVM 大数据可用 Arrays.parallelSort(对象/原生数组)。Android 端一般不建议并行排序以免与主线程/电量打架;把重活挪到后台线程。
 
三、查找(Searching)
1) 线性查找(通用)
- 
indexOf/lastIndexOf/find:O(n) ,小列表或一次性查找可用。
 - 
Kotlin 流式:firstOrNull { it.id == target }。
 
2) 二分查找(已排序)
Java
            
            
              ini
              
              
            
          
          int idx = Collections.binarySearch(list, target, cmp);
if (idx >= 0) {
  // 找到了
} else {
  int insertionPoint = -idx - 1; // 未找到,应插入的位置
}
        Kotlin
            
            
              ini
              
              
            
          
          val idx = list.binarySearch(key = 123, comparator = compareBy<Item> { it.id })
        - 
必须同一比较逻辑 :排序与查找用同一 Comparator,否则结果未定义。
 - 
稳定插入 :list.add(insertionPoint, x) 实现边查边插维持有序。
 
3) 高频"包含/去重/按 id 查"
- 预建索引更高效:
 
            
            
              javascript
              
              
            
          
          val index: Map<Long, Item> = items.associateBy { it.id }  // O(n) 构建,O(1) 查
val set: Set<Long> = items.mapTo(hashSetOf()) { it.id }   // O(1) contains
        - 需要顺序 + 快查:LinkedHashMap 按插入/访问顺序 + O(1) 查找。
 
4) 前缀/模糊搜索(UI 实时)
- 小规模:lowerBound/upperBound 在已排序数组上做前缀范围。
 - 大规模或频繁:用 Trie / FST / 索引库;或把"搜索"后移到数据库/后端。
 
四、易踩坑 & 规约
- a - b 比较(可能溢出):
 
            
            
              rust
              
              
            
          
          // ❌
(o1, o2) -> o1.score - o2.score
// ✅
Comparator.comparingInt(Foo::getScore)
        - 比较器不自洽(非传递/不一致)会导致排序/二分/有序集合失效:
 
- 
保证 自反、反对称、传递,compare(a,b)==0 时尽可能与 equals 一致。
 - 
需要"稳定分组"时优先 稳定排序 + 明确二级/三级字段。
 
- 排序后用于二分但 Comparator 不同 → 结果未定义(可能错位/死循环)。
 - subList 排序 :subList 是父列表的视图,排序/修改会作用于父列表;跨结构修改可能抛 CME(见 fail-fast 规则)。
 - UI 列表闪烁:排序后直接 notifyDataSetChanged() 会整表重绘;用 DiffUtil 或 ListAdapter 计算差异。
 
五、常用范式代码
1) "时间倒序 + 同时长升序 + 置顶优先"
            
            
              less
              
              
            
          
          val collator = Collator.getInstance(Locale.getDefault())
items.sortWith(
  compareByDescending<Item> { it.pinned }               // 置顶
    .thenByDescending { it.publishTime }                // 时间新
    .thenBy { it.durationSec }                          // 时长短
    .thenComparator { a, b -> collator.compare(a.title, b.title) } // 本地化
)
        2) 维持有序插入(二分 + 插入点)
            
            
              kotlin
              
              
            
          
          fun MutableList<Int>.insertSorted(x: Int) {
  val pos = binarySearch(x)
  val i = if (pos >= 0) pos else -pos - 1
  add(i, x)
}
        3) 用户可见字符串排序(忽略大小写/重音)
            
            
              ini
              
              
            
          
          Collator c = Collator.getInstance(locale);
c.setStrength(Collator.PRIMARY); // 忽略大小写与重音
list.sort(Comparator.comparing(Item::getTitle, c));
        4) RecyclerView 排序后的增量刷新
            
            
              css
              
              
            
          
          val diff = DiffUtil.calculateDiff(object: DiffUtil.Callback() { /* ... */ })
items.sortWith(cmp)
diff.dispatchUpdatesTo(adapter)
        六、选型与流程建议
- 
一次性展示/小数据:sortedBy/sortWith 即可。
 - 
实时搜索/频繁增删:维持有序(二分插入)或改用 TreeSet/数据库 ORDER BY。
 - 
用户文本:一律 Collator;需要多语言按 Locale 切换。
 - 
"是否存在/按 id 找"高频:先建 HashSet/HashMap 索引。
 - 
端上性能:重活放后台协程;UI 层用 Diff 渐进更新。