維護一個按 sessionId 排序的集合,需快速判斷是否存在、不存在則插入、存在則計數 +1。二分查找將查詢/插入從 O(n) 降為 O(log n)。
Beanpackage uv;
public class Bean implements Comparable<Bean> {
private String sessionId;
private Integer num = 1;
public Bean(String sessionId) { this.sessionId = sessionId; }
public String getSessionId() { return sessionId; }
public void setSessionId(String sessionId) { this.sessionId = sessionId; }
public Integer getNum() { return num; }
public void setNum(Integer num) { this.num = num; }
public void increase() { ++num; }
@Override
public int compareTo(Bean o) {
return this.sessionId.compareTo(o.getSessionId()); // 按 sessionId 自然序
}
@Override
public String toString() { return sessionId; }
}
import java.util.ArrayList;
import java.util.List;
public class BinarySearchInsert {
private final List<Bean> list = new ArrayList<>();
/** 查找索引:存在回傳索引,不存在回傳 -(插入點) - 1 */
private int binarySearch(String sessionId) {
int lo = 0, hi = list.size() - 1;
while (lo <= hi) {
int mid = (lo + hi) >>> 1;
int cmp = list.get(mid).getSessionId().compareTo(sessionId);
if (cmp < 0) lo = mid + 1;
else if (cmp > 0) hi = mid - 1;
else return mid; // 找到
}
return -lo - 1; // 未找到,lo 為插入點
}
/** 插入或計數 +1 */
public void addOrIncrement(String sessionId) {
int idx = binarySearch(sessionId);
if (idx >= 0) {
list.get(idx).increase();
} else {
int insertPos = -idx - 1;
list.add(insertPos, new Bean(sessionId));
}
}
public List<Bean> getList() { return list; }
public static void main(String[] args) {
BinarySearchInsert bsi = new BinarySearchInsert();
bsi.addOrIncrement("s3");
bsi.addOrIncrement("s1");
bsi.addOrIncrement("s2");
bsi.addOrIncrement("s1"); // 重複
bsi.getList().forEach(System.out::println);
// 輸出: s1, s2, s3 (s1.num=2)
}
}
| 技術點 | 說明 |
|---|---|
Comparable<T> | 定義自然排序,Collections.binarySearch 要求列表已按此順序排序 |
| 插入點公式 | -insertionPoint - 1 是 Java 二分搜尋約定的未找到回傳值 |
>>> 1 | 無符號右移,等同 (lo+hi)/2 但避免溢位 |
| ArrayList 插入 | 中間插入 O(n) 位移,若頻繁插入建議用 LinkedList 或 TreeMap |
// TreeMap 一行解決
Map<String, Integer> map = new TreeMap<>();
map.merge(sessionId, 1, Integer::sum);