我的建議也是使用兩個HashMap
,但其中一個逐漸填滿,而不是增加它的排序複雜性來更新時間。這將提供以下屬性:
- 快速閱讀
byStudent
- 更新較慢O(N)。如果更新很多,可以考慮將
reorder
從addOrUpdate
方法中刪除,批量更新並在每批次之後從外部調用重新排序。
- 最終快速
byRank
閱讀。
class MyClass {
Comparator<RankedStudent> comp = Comparator.comparingInt(e -> e.marks);
private Map<String, RankedStudent> repo = new HashMap<>();
private Map<Integer, RankedStudent> rankCache = new HashMap<>();
public RankedStudent getByStudent(String student) {
return repo.get(student);
}
public RankedStudent getByRank(Integer rank) {
return Optional.ofNullable(rankCache.get(rank)).orElseGet(() -> {
rankCache.putIfAbsent(rank, repo.values().stream().sorted((s1, s2) -> rank == s1.rank ? 1 : 0)
.findFirst().orElse(null));
return rankCache.get(rank);
});
}
public void addOrUpdate(String student, Integer marks) {
repo.put(student, new RankedStudent(student, marks, -1));
reorder();
}
public void reorder() {
final Iterator<RankedStudent> it = repo.values().stream().sorted(comp.reversed()).iterator();
IntStream.range(0, repo.size()).boxed().forEach(i -> it.next().rank = i + 1);
rankCache.clear();
}
}
class RankedStudent {
public String name;
public int marks;
public int rank;
public RankedStudent(String name, int marks, int rank) {
this.name = name;
this.marks = marks;
this.rank = rank;
}
}
包含HashMap的(平均)O(1)操作,你所尋找的,所以你不能擊敗。但是,他們需要空間。 你可以做的是:創建一個名稱,標記(?一個或多個),等級的班級。然後兩個名字和級別的hashmaps指向該用戶的類。昂貴但有效。 – EsseTi
另一種選擇是擁有一個可比較的Name + Marks類,一個按等級自動排序的比較方法,以及一個簡單的List來存儲它們。優點:更新排名是自動的,更少的空間需求,代碼可能更容易閱讀。缺點:比hashmaps慢,訪問不是o(1)了。 – Joel
爲什麼不使用帶'name'和'marks'字段的'class Student'並通過'marks'反向排列學生列表來獲得排名?您還可以添加每次列表排序時重置的屬性「rank」。 –