如何在不使用可比较和比较器接口的情况下对地图进行排序?自定义排序怎么写?

问题- 我有一个学生班,它包含姓名、学号、三个科目分数 m1、m2、m3 和总分。如果两个或更多学生的分数相等,我需要根据他们的总分对学生对象进行排序,然后根据他们的姓名对其进行排序。注意- 我必须用谷歌搜索它,但在 stackoverflow 问题中没有得到预期的解决方案,每个问题都使用 Comparable 和 Comparator 接口。


我创建了 Studnt 类


public class Student {

    private String name;

    private Integer rollNumber;

    private int m1;

    private int m2;

    private int m3;

    private int totMarks;

    //Getter setter

}

主类


public class StudentData {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        System.out.println("Enetr the number of Student");

        int totalStudent = sc.nextInt();

        Map<Integer,Student> map = new TreeMap<Integer,Student>();

        for(int i =0;i<totalStudent;i++) {

            Student ss = new Student();

            System.out.println("Enter the Student roll number");

            ss.setRollNumber(sc.nextInt());

            System.out.println("Enter the Student Name");

            ss.setName(sc.next());

            System.out.println("Enter the m1 marks ");

            ss.setM1(sc.nextInt());

            System.out.println("Enetr the m2 marks ");

            ss.setM2(sc.nextInt());

            System.out.println("Enter the m3 marks ");

            ss.setM3(sc.nextInt());

            ss.setTotMarks(ss.getM1()+ss.getM2()+ss.getM3());


            map.put(ss.getTotMarks(),ss);

            ss=null;

        }   

        //stdList.forEach(System.out::print);

        for(Map.Entry<Integer,Student> m :map.entrySet()) {

            System.out.println(m);

        }


    }

}

实际上,我正在使用 TreeMap 它按键对值进行排序(总分是我的 TreeMap 中的键)。但两个或更多学生的分数相同。然后旧学生对象(值)被新学生替换,因为 Key 不允许重复


输出


6=学生 [姓名=ved, rollNumber=12, m1=2, m2=2, m3=2, totMarks=6]


9=学生 [姓名=prakash, rollNumber=56, m1=3, m2=3, m3=3, totMarks=9]


地图中存储的唯一唯一 totMarks


浮云间
浏览 104回答 3
3回答

UYOU

由于您不能使用现有的 Comparator 或排序算法,因此您需要自己完成。我已经实现了一个static函数lessOrEqual,它接受 2 个Student实例,比较它们并返回是否s1小于或等于s2。 larger(Student s1, Student s2)仅当s1大于时返回真s2。可以有很多不同的方法来做到这一点,这真的取决于你,因为它只是一个比较。该函数首先检查成绩,如果成绩匹配,它将检查姓名并相应地返回。编辑:如您所见,我替换lessOrEqual为larger因为我正在使用的选择排序需要找到larger。这是相同的效果,我这样做只是为了更好的可读性。然后我实现了另一个static接受ArrayList<Student>、排序并返回排序的函数。使用的排序算法非常基本:选择排序。它的 O(N^2) 效率不高,但为了简单起见,我在下面的演示中这样做了。代码:import java.util.ArrayList;&nbsp;public class Student {&nbsp; &nbsp; private String name;&nbsp; &nbsp; private Integer rollNumber;&nbsp; &nbsp; private int m1;&nbsp; &nbsp; private int m2;&nbsp; &nbsp; private int m3;&nbsp; &nbsp; private int totMarks;&nbsp; &nbsp; public static boolean larger(Student s1, Student s2){&nbsp; &nbsp; &nbsp; &nbsp; if(s1.totMarks < s2.totMarks) return false;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; else if (s1.totMarks > s2.totMarks) return true;&nbsp; &nbsp; &nbsp; &nbsp; // compare names&nbsp; &nbsp; &nbsp; &nbsp; else return s1.name.compareTo(s2.name) > 0;&nbsp; &nbsp; }&nbsp; &nbsp; public static ArrayList<Student> sortSelection(ArrayList<Student> list){&nbsp; &nbsp; &nbsp; &nbsp; for(int i=0; i<list.size(); i++){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(int j=i+1; j< list.size(); j++){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(larger(list.get(i), list.get(j))){ // swap&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Student temp = list.get(i);&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; list.set(i, list.get(j));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; list.set(j, temp);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return list;&nbsp; &nbsp; }&nbsp; &nbsp; //Getter setter&nbsp; &nbsp; public String getName(){&nbsp; &nbsp; &nbsp; &nbsp; return name;&nbsp;&nbsp; &nbsp; }&nbsp; &nbsp; public void setName(String name){&nbsp; &nbsp; &nbsp; &nbsp; this.name = name;&nbsp;&nbsp; &nbsp; }&nbsp; &nbsp; public int getTotMarks(){&nbsp; &nbsp; &nbsp; &nbsp; return totMarks;&nbsp; &nbsp; }&nbsp; &nbsp; public void setTotMarks(int totMarks){&nbsp; &nbsp; &nbsp; &nbsp; this.totMarks = totMarks;&nbsp;&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public String toString(){&nbsp; &nbsp; &nbsp; &nbsp; return String.format("Name: %20s - Total Marks: %3d", name, totMarks);&nbsp; &nbsp; }&nbsp; &nbsp; public static void main(String[] args){&nbsp; &nbsp; &nbsp; &nbsp; Student s1 = new Student();&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; Student s2 = new Student();&nbsp; &nbsp; &nbsp; &nbsp; Student s3 = new Student();&nbsp; &nbsp; &nbsp; &nbsp; Student s4 = new Student();&nbsp; &nbsp; &nbsp; &nbsp; s1.setName("John Smith");&nbsp; &nbsp; &nbsp; &nbsp; s1.setTotMarks(98);&nbsp; &nbsp; &nbsp; &nbsp; s2.setName("Jack Smith");&nbsp; &nbsp; &nbsp; &nbsp; s2.setTotMarks(98);&nbsp; &nbsp; &nbsp; &nbsp; s3.setName("Adam Noob");&nbsp; &nbsp; &nbsp; &nbsp; s3.setTotMarks(100);&nbsp; &nbsp; &nbsp; &nbsp; s4.setName("Ved Parkash");&nbsp; &nbsp; &nbsp; &nbsp; s4.setTotMarks(99);&nbsp; &nbsp; &nbsp; &nbsp; ArrayList<Student> list = new ArrayList<>();&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; list.add(s4);&nbsp; &nbsp; &nbsp; &nbsp; list.add(s3);&nbsp; &nbsp; &nbsp; &nbsp; list.add(s1);&nbsp; &nbsp; &nbsp; &nbsp; list.add(s2);&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Array before sorting:");&nbsp; &nbsp; &nbsp; &nbsp; for(int i=0; i<list.size(); i++){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(list.get(i).toString());&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; Student.sortSelection(list);&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Array after sorting:");&nbsp; &nbsp; &nbsp; &nbsp; for(int i=0; i<list.size(); i++){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(list.get(i).toString());&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}输出:Array before sorting:Name:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Ved Parkash - Total Marks:&nbsp; 99Name:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Adam Noob - Total Marks: 100Name:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;John Smith - Total Marks:&nbsp; 98Name:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Jack Smith - Total Marks:&nbsp; 98Array after sorting:Name:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Jack Smith - Total Marks:&nbsp; 98Name:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;John Smith - Total Marks:&nbsp; 98Name:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Ved Parkash - Total Marks:&nbsp; 99Name:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Adam Noob - Total Marks: 100笔记:1) 查看学生添加到列表中的顺序,它是 4,3, 1 然后是 2。这是为了证明它在成绩匹配时根据姓名排序(Jack Smith vs John Smith)。2) 我对学生进行硬编码以制作更好的演示。3) 正如您可能注意到的那样,我没有设置任何其他变量,因为问题完全是关于排序的,唯一对排序有贡献的变量是:name和totMarks。你将不得不做剩下的事情。4) 我正在使用ArrayList,但不限于此,通过简单的更改,您可以在普通Student[]数组上使用它。5)函数larger不一定是static,你可以把它做成一个成员函数,用不同的方式使用。例如,上面的代码将更改为:&nbsp; &nbsp; public boolean larger(Student other){&nbsp; &nbsp; &nbsp; &nbsp; if(totMarks < other.totMarks) return false;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; else if (totMarks > other.totMarks) return true;&nbsp; &nbsp; &nbsp; &nbsp; // compare names&nbsp; &nbsp; &nbsp; &nbsp; else return name.compareTo(other.name) > 0;&nbsp; &nbsp; }&nbsp; &nbsp; public static ArrayList<Student> sortSelection(ArrayList<Student> list){&nbsp; &nbsp; &nbsp; &nbsp; for(int i=0; i<list.size(); i++){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(int j=i+1; j< list.size(); j++){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // comparison way changes accordingly&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(list.get(i).larger(list.get(j))){ // swap&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Student temp = list.get(i);&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; list.set(i, list.get(j));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; list.set(j, temp);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return list;&nbsp; &nbsp; }

胡说叔叔

为了保持简单(即 KISS 原则)并解释我与复合键相关的“提示”,以下是工作示例。解决方案的“关键”是让树自然地对数据进行排序(不是,恕我直言,通过提供手动排序来添加代码使其变得更加复杂)。因此,学生类需要返回一个树可以自然排序的键。为了产生所需的排序结果,树的键是(总分,学生姓名)。这是修改后的 Student 类(减去 getter 和 setter,但我确实添加了一个新的构造函数以使我的生活更轻松):public class Student {&nbsp; &nbsp; private String name;&nbsp; &nbsp; private Integer rollNumber;&nbsp; &nbsp; private int m1;&nbsp; &nbsp; private int m2;&nbsp; &nbsp; private int m3;&nbsp; &nbsp; private int totMarks;&nbsp; &nbsp; //Getter setter&nbsp; &nbsp; public Student() {&nbsp; &nbsp; }&nbsp; &nbsp; public Student(String name, Integer rollNumber, int m1, int m2, int m3) {&nbsp; &nbsp; &nbsp; &nbsp; this.name = name;&nbsp; &nbsp; &nbsp; &nbsp; this.rollNumber = rollNumber;&nbsp; &nbsp; &nbsp; &nbsp; this.m1 = m1;&nbsp; &nbsp; &nbsp; &nbsp; this.m2 = m2;&nbsp; &nbsp; &nbsp; &nbsp; this.m3 = m3;&nbsp; &nbsp; &nbsp; &nbsp; this.totMarks = m1 + m2 + m3;&nbsp; &nbsp; }&nbsp; &nbsp; public String getKey() {//&nbsp; &nbsp; &nbsp; return String.format("%d-%s", totMarks, name);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // WRONG!&nbsp; &nbsp; &nbsp; &nbsp; return String.format("%04d-%s", totMarks, name);&nbsp; &nbsp; &nbsp; &nbsp; // Right&nbsp; &nbsp; }&nbsp; &nbsp; public String toString() {&nbsp; &nbsp; &nbsp; &nbsp; return String.format("%06d: %s - %d", rollNumber, name, totMarks);&nbsp; &nbsp; }}请注意,方法中有一行注释掉的代码getKey带有注释WRONG。这与我用个位数分数测试的暗示有关。尝试交换两行代码以查看正确和错误的结果。这是主要的,我删除了所有扫描仪的东西——再次让我的生活更轻松。希望您可以关注它并重新添加到您的扫描仪循环中。import java.util.Arrays;import java.util.List;import java.util.Map;import java.util.TreeMap;public class StudentData {&nbsp; &nbsp; public static void main(String[] args) {&nbsp; &nbsp; &nbsp; &nbsp; // Initialise a list of students (as I don't want to rekey all the details each&nbsp; &nbsp; &nbsp; &nbsp; // time I run the program).&nbsp; &nbsp; &nbsp; &nbsp; List<Student> studentList = Arrays.asList(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Student("Fred", 1, 2, 2, 2),&nbsp; &nbsp; &nbsp; /* Score of 6 */&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Student("John", 2, 2, 3, 3),&nbsp; &nbsp; &nbsp; /* Score of 8 */&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Student("Jane", 3, 20, 25, 30),&nbsp; &nbsp; &nbsp; /* Score of 75 */&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Student("Julie", 4, 20, 15, 10)&nbsp; &nbsp; &nbsp; /* Score of 45 */&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // add as many new students as you like, and reorder them&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // as much as you like to see if there is any difference in the&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // result (there shouldn't be).&nbsp; &nbsp; &nbsp; &nbsp; );&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Note the key of the tree is of type String - not Integer.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // This is the heart of the algorithm, the tree will be "sorted"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // on the natural key provided. This "natural key" is in fact&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // a compound key that is generated by combining the total score&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // and the student name.&nbsp; &nbsp; &nbsp; &nbsp; Map<String,Student> map = new TreeMap<String,Student>();&nbsp; &nbsp; &nbsp; &nbsp; for (Student ss : studentList) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; map.put(ss.getKey(),ss);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; //stdList.forEach(System.out::print);&nbsp; &nbsp; &nbsp; &nbsp; for(Map.Entry<String,Student> m :map.entrySet()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(m);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}我希望您同意这是一个更简单的解决方案。还有一个潜在的性能优势,因为学生在被加载到树中时被排序(即一次)。我认为这种排序的性能是 log(n)。检索排序可能是 n log(n) 或更糟。

翻过高山走不出你

不是将值存储为 student,而是将它们存储为 (name, student) 的映射,这样当遇到具有相同标记的学生时,就会将其添加到映射中。public static void main(String[] args) {&nbsp; &nbsp; Scanner sc = new Scanner(System.in);&nbsp; &nbsp; System.out.println("Enetr the number of Student");&nbsp; &nbsp; int totalStudent = sc.nextInt();&nbsp; &nbsp; Map<Integer, Map<String, Student>> map = new TreeMap<>();&nbsp; &nbsp; for(int i =0;i<totalStudent;i++) {&nbsp; &nbsp; &nbsp; &nbsp; Student ss = new Student();&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Enter the Student roll number");&nbsp; &nbsp; &nbsp; &nbsp; ss.setRollNumber(sc.nextInt());&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Enter the Student Name");&nbsp; &nbsp; &nbsp; &nbsp; ss.setName(sc.next());&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Enter the m1 marks ");&nbsp; &nbsp; &nbsp; &nbsp; ss.setM1(sc.nextInt());&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Enetr the m2 marks ");&nbsp; &nbsp; &nbsp; &nbsp; ss.setM2(sc.nextInt());&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("Enter the m3 marks ");&nbsp; &nbsp; &nbsp; &nbsp; ss.setM3(sc.nextInt());&nbsp; &nbsp; &nbsp; &nbsp; ss.setTotMarks(ss.getM1()+ss.getM2()+ss.getM3());&nbsp; &nbsp; &nbsp; &nbsp; Integer key = ss.getTotMarks();&nbsp; &nbsp; &nbsp; &nbsp; if (map.get(key) == null){&nbsp; // if this is a new key in the map, then create a new TreeMap and put it&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; final TreeMap<String, Student> nameAndStudentMap = new TreeMap<>();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nameAndStudentMap.put(ss.getName(), ss);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; map.put(key, nameAndStudentMap);&nbsp; &nbsp; &nbsp; &nbsp; }else { // if the key already existed, then get the map stored and add to it.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; map.get(key).put(ss.getName(), ss);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; //stdList.forEach(System.out::print);&nbsp; &nbsp; for(Map.Entry<Integer,Map<String, Student>> m :map.entrySet()) {&nbsp; &nbsp; &nbsp; &nbsp; for (Map.Entry<String, Student> nameAndStudent : m.getValue().entrySet()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(m.getKey() + " = " + nameAndStudent.getValue());&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java