我有以下学生的相关标记和等级信息
Name Marks Rank
A 30 1
B 20 2
C 10 3
学生的等级与学生的分数成反比。我必须找到最佳的数据结构来存储上述信息,以便以最佳方式执行以下操作(最佳时间复杂度)。可以假设学生姓名是唯一的。
我正在考虑使用两个哈希映射,一个用于学生并标记映射,另一个用于学生姓名和排名映射。这有更好的数据结构吗?有没有办法可以利用秩与标记成反比的事实。
答案 0 :(得分:6)
这可以通过两种数据结构来完成:
这允许您在O(logn)
中执行以下所有操作:
此外,仅使用哈希地图在O(1)
(平均情况)中查找学生成绩。
注意:
您可以将学生姓名>成绩图的实现切换为树形图而不是哈希图,而不会过多地影响复杂性,并保证更好的最坏情况行为。 (通过此更改,找到等级也将是O(logn)而不是O(1)。
答案 1 :(得分:2)
我的建议也是使用两个HashMap
,但其中一个是逐渐填充的,而不是添加它的排序复杂性来更新时间。这将提供以下属性:
byStudent
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;
}
}