存储标记和学生等级的最佳数据结构

时间:2015-06-24 09:45:35

标签: java algorithm data-structures time-complexity

我有以下学生的相关标记和等级信息

Name   Marks  Rank
 A      30     1
 B      20     2
 C      10     3

学生的等级与学生的分数成反比。我必须找到最佳的数据结构来存储上述信息,以便以最佳方式执行以下操作(最佳时间复杂度)。可以假设学生姓名是唯一的。

  1. 给出学生姓名,找到分数和等级
  2. 鉴于排名,找到学生的标记和姓名
  3. 更新学生的分数。
  4. 我正在考虑使用两个哈希映射,一个用于学生并标记映射,另一个用于学生姓名和排名映射。这有更好的数据结构吗?有没有办法可以利用秩与标记成反比的事实。

2 个答案:

答案 0 :(得分:6)

这可以通过两种数据结构来完成:

  1. 从学生姓名到成绩的哈希地图
  2. order statistic tree 的学生,比较的关键是成绩。
  3. 这允许您在O(logn)中执行以下所有操作:

    1. 找到学生的排名:在哈希映射中找到它,然后在树中找到它的顺序统计(排名)。
    2. 更新学生成绩:在地图中找到他的旧成绩,将其从地图和树中删除,然后使用新值重新插入。
    3. 根据排名,使用订单统计树查找相关学生及其成绩。
    4. 此外,仅使用哈希地图在O(1)(平均情况)中查找学生成绩。

      注意:

      您可以将学生姓名>成绩图的实现切换为树形图而不是哈希图,而不会过多地影响复杂性,并保证更好的最坏情况行为。 (通过此更改,找到等级也将是O(logn)而不是O(1)。

答案 1 :(得分:2)

我的建议也是使用两个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;
    }
}