【问题标题】:Best Data Structure to store marks and ranks of students存储学生分数和等级的最佳数据结构
【发布时间】:2015-09-10 10:56:30
【问题描述】:

我有以下学生的相应分数和等级的信息

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

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

  1. 给定学生姓名,查找分数和排名
  2. 给定等级,找到学生的分数和姓名
  3. 更新学生的分数。

我正在考虑使用两个哈希映射,一个用于学生和标记映射,另一个用于学生姓名和排名映射。有没有更好的数据结构呢?有没有办法可以利用排名与分数成反比的事实。

【问题讨论】:

  • 哈希图对于您要查找的操作(平均而言)是 O(1),因此您无法击败它。然而,它们需要空间。您可以做的是:创建一个具有名称、标记(?一个或多个)、排名的类。然后是两个用于 name 和 rank 的 hashmaps 指向该用户的类。昂贵但有效。
  • 另一种选择是有一个 Name + Marks 的 Comparable 类,一个按排名自动排序的比较方法,以及一个简单的 List 来存储它们。优点:更新排名是自动的,需要的空间更少,代码可能更易于阅读。缺点:比 hashmap 慢,访问不再是 o(1)。
  • 为什么不使用class Student 字段namemarks 并通过marks 对学生列表进行反向排序来获得排名?您还可以添加一个属性 rank,该属性会在每次列表排序时重置。
  • 基本列表不太适合排序。为什么每次都对列表​​进行排序,而您可以使用最大堆优先级队列或类似的东西;-)。
  • 你应该使用某种排序的地图,使用你的班级学生,它应该有字段来存储姓名、分数和排名。理想情况下,这应该实现Comparable 并覆盖compare 方法,以便地图可以进行比较。我希望TreeMap 应该这样做。

标签: java algorithm data-structures time-complexity


【解决方案1】:

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

  1. 一个哈希图,将学生姓名映射到他的年级。
  2. order statistic tree 的学生,比较的关键是成绩。

这允许您在O(logn) 中执行以下所有操作:

  1. 查找学生的排名:在哈希图中查找,然后在树中查找其顺序统计量(排名)。
  2. 更新学生成绩:在地图中找到他的旧成绩,将其从地图和树中删除,然后使用新值重新插入。
  3. 给定排名,使用顺序统计树查找相关学生及其成绩。

此外,在O(1)(平均情况)中仅使用哈希映射即可查找学生的成绩。


注意:

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

【讨论】:

    【解决方案2】:

    我的建议也是使用两个HashMap,但其中一个是逐渐填充的,而不是增加它的排序复杂性来更新时间。这将提供以下属性:

    • 快速阅读byStudent
    • 较慢的更新 O(n)。如果更新很多,可以考虑将reorderaddOrUpdate方法中拉出来,分批更新,每批后从外部调用reorder。
    • 最终快速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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多