[Java] PriorityQueue를 for-each문으로 꺼내보면?

하원·2025년 5월 4일
post-thumbnail

안녕하세요, 하원입니다.
오늘은 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 와 같은 결과가 출력되었습니다. 왜 그런 걸까요?


원인

1. PriorityQueue 구조

  • PriorityQueue는 힙(Heap)의 구조로 데이터를 저장합니다.
  • 위 코드는 내림차순이기 때문에 최대 힙(Max Heap) 구조를 가지고 있습니다.
  • 최대 힙 : 각 노드가 자식 노드들보다 크거나 같은 값을 가지는 트리 구조

-> 즉, poll()이나 peek()를 사용해야 우선순위에 맞게 데이터를 조회할 수 있는 것입니다.

2. for-each(=iterator)의 순회 방식

  • for-each문은 iterator()를 호출합니다.
  • iterator() : 내부의 배열 순서 그대로 순회하게 됩니다.
  • poll() : 힙의 루트(=최소 또는 최대)에서 값을 하나씩 꺼냅니다.
  • 힙의 루트와 나머지 값들은 사용자가 지정한 최소 힙, 최대 힙에 따라 값을 유지하게 됩니다.

-> 즉, 내부 배열 구조는 힙 조건을 만족하는 구조일 뿐, 정렬된 순서는 아니라는 의미입니다.


해결 방법

1. poll() 또는 peek() 사용

        while (!descQueue.isEmpty()) {
            System.out.print(descQueue.poll() + " ");
        }
  • poll() 또는 peek()를 사용해서 Queue 안에 있는 데이터들을 모두 꺼내 주시면 순서가 보장됩니다.

2. for문보다 while문을 사용

		// 잘못된 예시
        for (int i = 0; i < descQueue.size(); i++) {
            System.out.print(descQueue.poll() + " ");
        }
  • 생각 없이 코드를 작성하다 보면 위와 같은 실수를 할 때도 있어서, Queue에서 데이터를 꺼낼 때는 개인적으로 for문 또는 for-each문을 지양하는 편입니다.

for-each문

이전 포스팅에서도 for-each문을 사용하면서 발생할 수 있는 ConcurrentModificationException 오류에 대해 소개해 드렸는데요, 이번에도 for-each문 관련 포스팅을 작성하게 되었습니다.

코딩 테스트를 진행할 때는 되도록 for-each문보다 for문 또는 while문을 사용하는 게 더 안전하지 않을까 싶습니다. 아무래도 빠른 시간 안에 문제를 풀다 보면 이러한 유의 사항들을 고려하기 쉽지 않아서, 개인적으로 for문이나 while문을 사용해야겠다고 생각하게 되는 것 같습니다.


마무리

Java는 익숙하면서도 여전히 속을 알기 어려운 언어인 것 같다. for문, for-each문, while문 등 반복문마다 미묘한 차이점이 있다는 게 흥미롭기도 하다. 이러한 차이점들을 얼른 더 배워서 내 언어로 만들고 싶다.

profile
호기심 저장소

0개의 댓글