백준문제풀이

2022.06.29 백준 Q1927

이루나을 2022. 6. 30. 21:48

학습 내용 : 최소 힙 구현, PriorityQueue API를 이용한 최소힙 구현

이 문제는 최소 힙을 구현하는 문제이다. 필자는 API 사용 없이 구현을 한 후에 API를 사용해 구현하였다.

static void addData(int data){
    int currentIndex = ++size;
    while (currentIndex != 1 && list[currentIndex / 2] > data) {
        list[currentIndex] = list[currentIndex / 2];
        currentIndex = currentIndex / 2;
    }
    list[currentIndex] = data;
}

위 코드는 addData를 구현한 코드이다.

currentIndex = ++size를 해 size를 하나 늘려주고 list 끝에 데이터를 넣는다(바로 다음에 swap될 수 있으므로 실제로 넣진 않는다. currentIndex가 1이 아니고(root Index는 더이상 위로 올라갈 수 없기 때문에) list[current/2[(부모 노드)가 data보다 크면 최소 힙을 만족시키기 위해 부모 노드와 자식 노드를 바꾼다(바로 또 바뀔 수 있기 때문에 복잡도를 줄이기 위해 부모 노드만 자식 노드에 넣어놨다). 그 후 부모노드의 부모노드와 비교하기 위해

currentIndex = currentIndex / 2;

를 한다.

 

만약 부모노드가 data보다 작으면 최소힙이 만족하기 때문에 반복문을 빠져나가고 현재 index에 data를 넣어 함수를 종료한다.

 

static void deleteData(){
    if(size==0){
        sb.append(0).append("\n");
        return;
    }
    sb.append(list[1]).append("\n");
    int data = list[size--];
    int currentIndex = 1;
    int child = 2;
    while(child<=size){
        if(child<size&&list[child]>list[child+1]) child++;
        if(data<=list[child]) break;
        list[currentIndex] = list[child];
        currentIndex =child;
        child*=2;
    }
    list[currentIndex] =data;

}

다음은 노드 삭제 함수이다. 첫번째 Index값이 제일 작은 값이므로 그 값을 삭제한다(동시에 출력해준다). 제일 마지막에 있는 노드를 루트 노드에 올리고 size--한다.

반복문에서 child>size면 자식 노드가 없는 것이기 때문에 반복문을 종료한다. child<size(오른쪽 자식이 존재하는지 확인)

일때 왼쪽 자식노드가 오른쪽 자식 노드보다 크면 child++로 오른쪽 자식과 부모 노드를 비교하게 셋팅한다.

만약 data가 더 작다면 최소힙이 만족하기 때문에 반복문을 종료하고 그 것이 아니라면 자식 노드를 부모 노드에 넣고 

currentIndex =child;
child*=2;

후 다시 반복문을 실행한다.

반복문이 끝났다면 현재 노드에 data를 넣어준다.

 

 

-구현 코드-

package BaekJoon1927;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    static int[] list;
    static int size =0;
    static StringBuilder sb = new StringBuilder();
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int num = Integer.parseInt(br.readLine());
        list = new int[num];

        for(int i=0;i<num;i++){
            int data = Integer.parseInt(br.readLine());
            if(data==0) deleteData();
            else addData(data);
        }
        System.out.println(sb);
    }


    static void deleteData(){
        if(size==0){
            sb.append(0).append("\n");
            return;
        }
        sb.append(list[1]).append("\n");
        int data = list[size--];
        int currentIndex = 1;
        int child = 2;
        while(child<=size){
            if(child<size&&list[child]>list[child+1]) child++;
            if(data<=list[child]) break;
            list[currentIndex] = list[child];
            currentIndex =child;
            child*=2;
        }
        list[currentIndex] =data;

    }
    static void addData(int data){
        int currentIndex = ++size;
        while (currentIndex != 1 && list[currentIndex / 2] > data) {
            list[currentIndex] = list[currentIndex / 2];
            currentIndex = currentIndex / 2;
        }
        list[currentIndex] = data;
    }
}

 

 

 

아래 코드는 API를 사용해 구현한 코드이다

package BaekJoon1927;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.PriorityQueue;

public class MakeWithPriorityQueue {
    static StringBuilder sb = new StringBuilder();
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int num = Integer.parseInt(br.readLine());
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        for(int i=0;i<num;i++){
            int data = Integer.parseInt(br.readLine());
            if(data==0) {
                if(queue.isEmpty()) sb.append(0).append("\n");
                else {
                    sb.append(queue.poll()).append("\n");
                }
            }
            else{
                queue.add(data);
            }
        }
        System.out.println(sb);
    }
}

 

우선순위큐는 기본적으로 작은 것 부터 빠져나가기 때문에 최소힙과 같은 동작원리이다. 따라서 넣을 때는 queue.add(data)로 넣고 삭제할때는 queue.poll()로 큐에서 빼면 된다.

만약 다른 방식대로 우선순위를 정하고 싶을때는 comparator나 comparable로 그 조건을 바뀌어준다.