题目链接

结构体优先队列

题目描述

你需要管理一个学生成绩系统,支持以下三种操作:

  1. 插入: 1 x y z,登记一个新学生的成绩(语文 x,数学 y,外语 z)。
  2. 查询: 2,输出当前系统中"成绩最好"的学生的各项成绩。
  3. 删除: 3,删除当前系统中"成绩最好"的学生的记录。

这是一个主函数模式的题目,你需要自己处理输入和输出。

"成绩最好"的判定规则按以下优先级顺序比较:

  1. 总成绩高者优先。
  2. 若总成绩相同,则语文成绩高者优先。
  3. 若总成绩和语文成绩都相同,则数学成绩高者优先。
  4. 若以上三项都相同,则外语成绩高者优先。
  5. 如果所有成绩都相同,可以认为是并列的,删除时只删除一个。

示例: 输入:

10
1 93 27 6
2
3
1 31 46 2
1 100 85 84
2
2
1 2 40 3
2
2

输出:

93 27 6
100 85 84
100 85 84
100 85 84
100 85 84

解题思路

这个问题需要我们动态地找到并移除集合中的"最大值",这里的"最大值"由一个多层级的复杂规则定义。这正是**优先队列(最大堆)**的用武之地。

与上一题不同的是,我们现在要比较的不是单个整数,而是一个包含多项成绩的学生对象。因此,核心任务是教会优先队列如何根据我们的规则来比较两个学生对象。

自定义比较逻辑

  • C++: 填充题目模板提供的 operator< 自由函数。要让 std::priority_queue(默认最大堆)正常工作,a < b 必须定义为 "a 的优先级是否低于 b"。然后,在 insertValue, deleteValue, getTop 函数中分别实现对全局优先队列的 push, pop, top 操作。
  • Java: 填充 PriorityQueue 构造函数中匿名 Comparatorcompare 方法。因为 Java 的 PriorityQueue 默认是最小堆,我们需要让 compare(a, b)a 优于 b 时返回一个负数,从而模拟最大堆的行为。然后,在 insertValue, deleteValue, getTop 函数中分别实现对全局优先队列的 add, poll, peek 操作。
  • Python: heapq 模块实现的是最小堆。我们通过在 Student 类中实现 __lt__ (less than) 方法来定义比较规则。为了让成绩最好的学生被认为是"最小"的元素而浮到堆顶,self < other 的逻辑必须定义为 "self 的成绩是否优于 other"。然后,在 insertValue, deleteValue, getTop 函数中分别调用 heapq.heappush, heapq.heappop 和访问 s[0]

算法步骤:

  1. 根据模板要求,在指定位置(operator<, Comparator, 或 __lt__)实现多级比较逻辑。
  2. insert, delete, get 函数中封装对全局优先队列的相应操作。
  3. 主函数会调用这些封装好的函数来完成整个流程。

代码

#include<bits/stdc++.h>
using namespace std;

struct node{
    int chinese, math, english, sum;
};

bool operator<(node a, node b){
    if (a.sum != b.sum) return a.sum < b.sum;
    if (a.chinese != b.chinese) return a.chinese < b.chinese;
    if (a.math != b.math) return a.math < b.math;
    return a.english < b.english;
}

priority_queue<node> s;

void insertValue(int chinese, int math, int english){
    s.push({chinese, math, english, chinese + math + english});
}

void deleteValue(){
    if (!s.empty()) {
        s.pop();
    }
}

node getTop(){
    if (!s.empty()) {
        return s.top();
    }
    return {}; // Should not be reached given problem constraints
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int q,op;
    int x, y, z;
    cin>>q;
    while(q--){
        cin>>op;
        if(op==1){
            cin>>x>>y>>z;
            insertValue(x, y, z);
        }
        if(op==2){
            node tmp = getTop();
            cout<<tmp.chinese<<" "<<tmp.math<<" "<<tmp.english<<endl;
        }
        if(op==3){
           deleteValue();
        }
    }
    return 0;
}
import java.util.*;

class Student {
    int chinese, math, english, sum;
    
    public Student(int chinese, int math, int english) {
        this.chinese = chinese;
        this.math = math;
        this.english = english;
        this.sum = chinese + math + english;
    }
}

public class Main {
    // 使用Java的PriorityQueue实现成绩排序
    static PriorityQueue<Student> s = new PriorityQueue<>(new Comparator<Student>() {
        @Override
        public int compare(Student a, Student b) {
            // 返回负数表示 a 的优先级更高
            if (a.sum != b.sum) return b.sum - a.sum;
            if (a.chinese != b.chinese) return b.chinese - a.chinese;
            if (a.math != b.math) return b.math - a.math;
            return b.english - a.english;
        }
    });
    
    public static void insertValue(int chinese, int math, int english) {
        s.add(new Student(chinese, math, english));
    }

    public static void deleteValue() {
        if (!s.isEmpty()) {
            s.poll();
        }
    }

    public static Student getTop() {
        if (!s.isEmpty()) {
            return s.peek();
        }
        return null;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int q = scanner.nextInt();
        while (q-- > 0) {
            int op = scanner.nextInt();
            if (op == 1) {
                int chinese = scanner.nextInt();
                int math = scanner.nextInt();
                int english = scanner.nextInt();
                insertValue(chinese, math, english);
            }
            if (op == 2) {
                Student top = getTop();
                if (top != null) {
                    System.out.println(top.chinese + " " + top.math + " " + top.english);
                }
            }
            if (op == 3) {
                deleteValue();
            }
        }
        scanner.close();
    }
}
import heapq

class Student:
    def __init__(self, chinese, math, english):
        self.chinese = chinese
        self.math = math
        self.english = english
        self.sum = chinese + math + english
    
    # heapq 是最小堆,成绩好的学生需要被认为是"更小"的
    def __lt__(self, other):
        if self.sum != other.sum:
            return self.sum > other.sum
        if self.chinese != other.chinese:
            return self.chinese > other.chinese
        if self.math != other.math:
            return self.math > other.math
        return self.english > other.english

# 使用Python的heapq模块实现优先队列
s = []

def insertValue(chinese, math, english):
    student = Student(chinese, math, english)
    heapq.heappush(s, student)

def deleteValue():
    if s:
        heapq.heappop(s)

def getTop():
    if s:
        return s[0]
    return None

if __name__ == "__main__":
    q = int(input())
    for _ in range(q):
        line = input().split()
        op = int(line[0])
        if op == 1:
            chinese = int(line[1])
            math = int(line[2])
            english = int(line[3])
            insertValue(chinese, math, english)
        elif op == 2:
            top = getTop()
            if top:
                print(f"{top.chinese} {top.math} {top.english}")
        elif op == 3:
            deleteValue()

算法及复杂度

  • 数据结构: 优先队列(最大堆)
  • 时间复杂度: 对于 次操作,每次操作(插入、删除)最多花费 时间,其中 是队列中当前的元素数量。查询最大值是 。总时间复杂度为
  • 空间复杂度: ,在最坏情况下,所有操作都是插入操作,需要存储 个学生对象。