안녕하세요, 하원입니다.
오늘은 PriorityQueue를 for-each문으로 꺼냈을 경우 발생하는 현상에 대해 소개해 보겠습니다.
이번에도 코딩 테스트를 진행하던 도중 발견한 현상이었는데요..!
PriorityQueue에 우선순위 조건을 설정하고 데이터를 삽입한 이후, for-each문으로 꺼내면 당연히 우선순위 조건에 맞는 순서로 조회될 것이라고 생각했습니다.
하지만 아니었습니다.
문제 상황
PriorityQueue<Integer> descQueue = new PriorityQueue<>(Collections.reverseOrder());
descQueue.add(4);
descQueue.add(3);
descQueue.add(1);
descQueue.add(2);
// 예상 결과 : 4 3 2 1
// 실제 결과 : 4 3 1 2
for(Integer number : descQueue) {
System.out.print(number + " ");
}
위 코드처럼 Collections.reverseOrder()를 통해 우선순위 큐에 내림차순 조건을 설정했습니다.
제 논리대로라면 4 3 2 1 과 같은 결과가 나올 것이라고 예상했습니다.
하지만 결과는 4 3 1 2 와 같은 결과가 출력되었습니다. 왜 그런 걸까요?
원인
-> 즉, poll()이나 peek()를 사용해야 우선순위에 맞게 데이터를 조회할 수 있는 것입니다.
iterator()를 호출합니다.iterator() : 내부의 배열 순서 그대로 순회하게 됩니다.poll() : 힙의 루트(=최소 또는 최대)에서 값을 하나씩 꺼냅니다.-> 즉, 내부 배열 구조는 힙 조건을 만족하는 구조일 뿐, 정렬된 순서는 아니라는 의미입니다.
해결 방법
while (!descQueue.isEmpty()) {
System.out.print(descQueue.poll() + " ");
}
poll() 또는 peek()를 사용해서 Queue 안에 있는 데이터들을 모두 꺼내 주시면 순서가 보장됩니다. // 잘못된 예시
for (int i = 0; i < descQueue.size(); i++) {
System.out.print(descQueue.poll() + " ");
}
for-each문
이전 포스팅에서도 for-each문을 사용하면서 발생할 수 있는 ConcurrentModificationException 오류에 대해 소개해 드렸는데요, 이번에도 for-each문 관련 포스팅을 작성하게 되었습니다.
코딩 테스트를 진행할 때는 되도록 for-each문보다 for문 또는 while문을 사용하는 게 더 안전하지 않을까 싶습니다. 아무래도 빠른 시간 안에 문제를 풀다 보면 이러한 유의 사항들을 고려하기 쉽지 않아서, 개인적으로 for문이나 while문을 사용해야겠다고 생각하게 되는 것 같습니다.
마무리
Java는 익숙하면서도 여전히 속을 알기 어려운 언어인 것 같다. for문, for-each문, while문 등 반복문마다 미묘한 차이점이 있다는 게 흥미롭기도 하다. 이러한 차이점들을 얼른 더 배워서 내 언어로 만들고 싶다.