2017-10-23 3 views
6

PriorityQueue와 저의 Comparator를 사용하고 있습니다 만, 어떻게 든 최종 결과가 항상 좋은 것은 아닙니다. id.no보다 이름보다는 등급 평균별로 정렬해야합니다. 마지막에 주문 된 대기열에 남아있는 이름을 반환해야합니다. 나머지 이름은 괜찮지 만 명령은 그렇지 않습니다. 입력 (이름, 학년 평균, id.no) :커스텀 Comparator를 사용한 Java PriorityQueue

add John 3,75 50 
add Mark 3,8 24 
add Shafaet 3,7 35 
poll 
poll 
add Samiha 3,85 36 
poll 
add Ashley 3,9 42 
add Maria 3,6 46 
add Anik 3,95 49 
add Dan 3,95 50 
poll 

예상 출력 :

Dan 
Ashley 
Shafaet 
Maria 

내 결과 :

Dan 
Ashley 
Maria 
Shafaet 

이 문제를 발견하는 데 도움이 시겠어요? 미리 감사드립니다.

class StComp implements Comparator<Students> { 
     @Override 
     public int compare(Students st1, Students st2) { 
      if (st1.getCgpa() == st2.getCgpa()) { 
       if (st1.getName().equals(st2.getName())) 
        return st1.getId() - st2.getId(); 
       else 
        return st1.getName().compareTo(st2.getName()); 
      } 
      else 
       return (st1.getCgpa() < st2.getCgpa()) ? 1 : -1; 
     } 
    } 

    StComp stComp = new StComp(); 
    PriorityQueue<Students> pq = new PriorityQueue<Students>(2, stComp); 
+0

'st1.getCgpa()'유형을 반환합니까? 'Double','double','BigDecimal'? –

+0

int id; 문자열 이름; 이중 cgpa; – Kokufuu

+1

'st1.getCgpa() == st2.getCgpa()'는'double'과 크게 다르지 않습니다. cgpa 대신에'BigDecimal'을 사용해보십시오 –

답변

1

Comparator이 정확한지 확인하십시오. 문제는 귀하가 Iterator을 사용하여 목록을 훑어 본다는 것입니다. PriorityQueue documentation 상태 :

반복자 방법 반복자 제공()는 임의의 특정 순서로 우선 순위 큐의 요소 이송 보장되지 않는다.이처럼 PriorityQueue을 반복한다면

, 당신은 올바른 결과를 볼 수 :

while (!pq.isEmpty()) 
    System.out.println(pq.poll().getName()); 
} 

나는 완전히 입증이 답변의 끝에 예를 포함 시켰습니다.


PriorityQueue을 삭제하고 싶지 않은 경우 몇 가지 조치를 취할 수 있습니다. 개인적으로 나는이 방법을 사용하지 않는 편이 바람직하기 때문에 PriorityQueue의 초기 선택이 유스 케이스에 맞지 않기 때문에이 방법을 사용하지 않는 것이 좋습니다. 다음 다시 추가,

Student[] students = pq.toArray(new Student[pq.size()]); 
Arrays.sort(students, new StComp()); 
for (Student s : students) { 
    System.out.println(s.getName() + " " + s.getCgpa() + " " + s.getId()); 
} 

또는 폴링 동안 Collection의 일종에 추가 :

당신은 정렬 된 배열을 반복, 당신의 Comparator 구현을 사용하여 예를 들어 그들을 분류, 배열로 PriorityQueue를 복사 할 수 PriorityQueue에, 예를 들면 :

Collection<Student> temp = new LinkedList<>(); 
while (!pq.isEmpty()) { 
    Student s = pq.poll(); 
    System.out.println(s.getName() + " " + s.getCgpa() + " " + s.getId()); 
    temp.add(s); 
} 
pq.addAll(temp); 

이 예는 데이터를 사용하여 설명하기 :,992,967,

public class Main { 

    public static void main(String[] args) { 
     PriorityQueue<Student> pq = new PriorityQueue<>(new StComp()); 
     pq.add(new Student("John", 75, 50)); // Student name, grade average, id 
     pq.add(new Student("Mark", 8, 24)); 
     pq.add(new Student("Shafaet", 7, 35)); 
     pq.poll(); 
     pq.poll(); 
     pq.add(new Student("Samiha", 85, 36)); 
     pq.poll(); 
     pq.add(new Student("Ashley", 9, 42)); 
     pq.add(new Student("Maria", 6, 46)); 
     pq.add(new Student("Anik", 95, 49)); 
     pq.add(new Student("Dan", 95, 50)); 
     pq.poll(); 

     // Not guaranteed to be in priorty order 
     System.out.println("Using PriorityQueue's Iterator, may not be in the correct priority order."); 
     for (Student s : pq) { 
      System.out.println(s.getName() + " " + s.getCgpa() + " " + s.getId()); 
     } 

     // Correct order, but removes from the Priority Queue 
     System.out.println("\nIterating until empty using PriorityQueue.poll(), will be in the correct order."); 
     while (!pq.isEmpty()) { 
      Student s = pq.poll(); 
      System.out.println(s.getName() + " " + s.getCgpa() + " " + s.getId()); 
     } 
    } 

} 

학생 홈페이지

public class Student { 

    private double cgpa; 
    private String name; 
    private int id; 

    public Student(String name, double cgpa, int id) { 
     this.name = name; 
     this.cgpa = cgpa; 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 

    public int getId() { 
     return id; 
    } 

    public double getCgpa() { 
     return cgpa; 
    } 

} 

StComp (질문에서 변경되지 않은 논리)

public class StComp implements Comparator<Student> { 

    @Override 
    public int compare(Student st1, Student st2) { 
     if (st1.getCgpa() == st2.getCgpa()) { 
      if (st1.getName().equals(st2.getName())) { 
       return st1.getId() - st2.getId(); 
      } else { 
       return st1.getName().compareTo(st2.getName()); 
      } 
     } else { 
      return (st1.getCgpa() < st2.getCgpa()) ? 1 : -1; 
     } 
    } 
} 
(이름, 단수이어야 함) 출력 (나를 적어도, 결과는 첫째 Iterator 변형에 따라 다를 수 있습니다에 대한)

Using PriorityQueue's Iterator, may not be in the correct priority order. 
Dan 95.0 50 
Ashley 9.0 42 
Maria 6.0 46 
Shafaet 7.0 35 

Iterating until empty using PriorityQueue.poll(), will be in the correct order. 
Dan 95.0 50 
Ashley 9.0 42 
Shafaet 7.0 35 
Maria 6.0 46 
1

자바 (8), 당신이 당신의 전체 비교기 클래스를 대체 할 수있다 : 당신은 자바의 이전 버전을 사용하는 경우

Comparator.comparingDouble(Students::getCgpa) 
    .thenComparing(Students::getName) 
    .thenComparingInt(Students::getId) 

, 또는 명시 적 비교기를 유지 주장, 당신은 반환해야합니다 동일한 값에 대해서는 0입니다. 또한 equals와 일치하는 이되도록 Comparator를 작성해야합니다. 가입일documentation : 요소 S 세트에 비교 c 의해 부과되는 순서가 알려져

c.compare(e1, e2)==0마다 e1e2위한 e1.equals(e2) 같은 부울 값을 갖는다 경우에만, 동일과 일치하도록 S.

정렬 된 집합 (또는 정렬 된지도)을 정렬하기 위해 equals와 일치하지 않는 순서를 적용 할 수있는 비교자를 사용할 때는주의해야합니다. 명시적인 컴퍼 레이터를 가지는 소트 세트 (또는 소트 맵)가 S로부터 꺼낸 요소 (또는 키)로 사용한다고 가정합니다. c에 의해 적용된 순서가 S 인 경우 equals와 일치하지 않으면 정렬 된 집합 (또는 정렬 된지도)이 "이상하게"작동합니다. 특히, 소트 세트 (또는 소트 맵)는, 세트 (또는 맵)의 일반 규약에 위반 해, equals로 정의되고 있습니다.

(두 객체가 동일한 경우를 비교할 때 즉, 비교기는 0을 반환해야합니다.)

@Override 
public int compare(Students st1, Students st2) { 
    int comparison = Double.compare(st1.getCgpa(), st2.getCgpa()); 
    if (comparison == 0) { 
     comparison = st1.getName().compareTo(st2.getName()); 
    } 
    if (comparison == 0) { 
     comparison = st1.getId() - st2.getId(); 
    } 
    return comparison; 
} 

이 당신의 학생 클래스가 일치 equals 방법이 있다고 가정합니다 :

@Override 
public boolean equals(Object obj) { 
    if (obj instanceof Students) { 
     Students other = (Students) obj; 
     return Double.compare(this.getCga(), other.getCga()) == 0 
      && this.getName().equals(other.getName()) 
      && this.getId() == other.getId(); 
    } 
    return false; 
}