자바/알고리즘

정렬 알고리즘 구현해 보기

2023. 12. 25. 06:22
글 목차


728x90

정렬 알고리즘을 구현해 봤다

버블, 셀렉, 삽입, 퀵, 병합, 힙

import java.util.ArrayList;
import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        int [] data = {3,5,2,1,7,9};
//        버블정렬(data);
//        선택정렬(data);
//        삽입정렬(data);
//        퀵정렬(data);
//        합병정렬(data);
    }
    /**
     * 버블 정렬을 구현해 봐요
     * <div>
     * 구현이 단순하나 O(N^2)로 비효율 적이에요
     * <br>
     * 안정정렬 이에요 (같은 값의 데이터의 순서는 유지되요)
     * </div>
     * @Author Okane
     * @Param data 정렬을 수행 할 배열이에요
     * @Return 정렬을 수행한 배열을 뱉어요
     */
    static void 버블정렬(int [] data) {
        System.out.println("버블소트에요!");
        for (int i = 0; i < data.length; i++) { // i는 소트 알고리즘의 회전수를 의미해요
            for (int j = 1; j < data.length; j++) {
                if (data[j-1] > data[j]) { // data를 한바퀴 돌면서 인접한 두 수의 크기를 비교해 스왑해 줘요
                    int a = data[j-1], b = data[j];
                    data[j-1] = b; data[j] = a;
                }
            }
        }
        System.out.println(Arrays.toString(data));
    }
    /**
     * <b>선택 정렬을 구현해 봐요</b>
     * <div>
     * 구현이 단순하나 O(N^2)로 비효율 적이에요
     * <br>
     * 불안정정렬 이에요(같은 값의 데이터의 순서가 유지되는 것이 보장되지 않아요)
     * </div>
     * @Author Okane
     * @Param data 정렬을 수행 할 배열이에요
     * @Return 정렬을 수행한 배열을 뱉어요
     */
    static void 선택정렬(int [] data) {
        System.out.println("선택정렬이에요!");
        for (int i = 0; i < data.length; i++) { // i는 해당 사이클에서 최소값을 넣을 index를 의미해요
            int min_index = -1;
            int min_value = Integer.MAX_VALUE;
            for (int j = i; j < data.length; j++) { // 해당 사이클에서 최소값을 찾아요
                if (min_value >= data[j]) {
                    min_index = j;
                    min_value = data[j];
                }
            }
            int temp = data[i];
            data[i] = min_value;
            data[min_index] = temp; // 골라진 최소값을 해당 사이클의 가장앞과 스왑해요
        }
        System.out.println(Arrays.toString(data));
    }

    /**
     * <b>삽입 정렬을 구현해 봐요</b>
     * <div>
     * 버블 소트와 비슷한 원리
     * <br>
     * 평균적과 최악은 O(n^2)로 비효율 적이나 최선의 경우(즉 데이터가 많이 정렬이 되있는 상태라면) O(n)로 효율적이에요
     * <br>
     * 안정정렬이에요
     * </div>
     * @Author Okane
     * @Param data 정렬을 수행 할 배열이에요
     * @Return 정렬을 수행한 배열을 뱉어요
     */
    static void 삽입정렬(int [] data) {
        System.out.println("삽입정렬이에요!");
        for (int i = 1; i < data.length; i++) { // i는 해당 사이클에서 정렬할 index값이에요
            for (int j = i-1; j >= 0; j--) {
                if (data[j] > data[j+1]) {
                    int temp = data[j];
                    data[j] = data[j+1];
                    data[j+1] = temp;
                    continue;
                }
                break;
            }
        }
        System.out.println(Arrays.toString(data));
    }
    /**
     * <b>퀵 정렬을 구현해 봐요</b>
     * <div>
     * 분할 정복을 사용하여 정렬을 구현하는 알고리즘이에요
     * <br>
     * 평균적으로 O(nlogn)으로 굉장히 속도가 빨라요
     * <br>
     * 불안정정렬이에요
     * </div>
     * @Author Okane
     * @Param data 정렬을 수행 할 배열이에요
     * @Return 정렬을 수행한 배열을 뱉어요
     */
    static void 퀵정렬(int [] data) {
        System.out.println("퀵 정렬이에요!");
        System.out.println(Arrays.toString(퀵정렬_도우미(data)));
    }

    static int [] 퀵정렬_도우미(int [] data) {
        if (data.length <= 1) return data; // 만약 피벗을 구할 필요가 없을 정도로 데이터가 짧다면 리턴해요
        int pivot = data[0]; // 기준을 정해요
        ArrayList<Integer> left = new ArrayList<>(), right = new ArrayList<>(); // 기준보다 적은건 left, 큰건 right에 넣어요
        for (int i = 1; i < data.length; i++) {
            if (data[i] <= pivot) left.add(data[i]);
            else right.add(data[i]);
        }
        int [] left_array = new int [left.size()]; // 배열로 타입변환
        for (int i = 0; i < left.size(); i++) {
            left_array[i] = left.get(i);
        }
        left_array = 퀵정렬_도우미(left_array); // 분할된 배열을 다시 헬퍼로 보내요
        int [] right_array = new int [right.size()]; // 배열로 타입변환
        for (int i = 0; i < right.size(); i++) {
            right_array[i] = right.get(i);
        }
        right_array = 퀵정렬_도우미(right_array); // 분할된 배열을 다시 헬퍼로 보내요

        int [] answer = new int [data.length]; // 답을 적을 배열을 선언해요
        for (int i = 0; i < left_array.length; i++) { // 기준을 기준으로 왼쪽을 채워요
            answer[i] = left_array[i];
        }
        answer[left_array.length] = pivot; // 기준을 채워요
        for (int i = left_array.length+1, j = 0; i < data.length; i++, j++) { // 기준을 기준으로 오른쪽을 채워요
            answer[i] = right_array[j];
        }
        return answer; // 리턴!
    }

    /**
     * <b>퀵 정렬을 구현해 봐요</b>
     * <div>
     * 분할 정복을 사용하여 정렬을 구현하는 알고리즘이에요
     * <br>
     * 평균적으로 O(nlogn)으로 굉장히 속도가 빨라요, 최악의 경우에도 nlogn의 성능을 내요
     * <br>
     * 안정정렬이에요
     * </div>
     * @Author Okane
     * @Param data 정렬을 수행 할 배열이에요
     * @Return 정렬을 수행한 배열을 뱉어요
     */
    static void 합병정렬(int [] data) {
        System.out.println("합병 정렬이에요");
        합병정렬_분할(data, 0, data.length-1);
        System.out.println(Arrays.toString(data));
    }
    static void 합병정렬_분할(int [] data, int left, int right) {
        if (left >= right) return;

        int mid = (right + left) / 2;
        합병정렬_분할(data, left, mid);
        합병정렬_분할(data, mid+1, right);
        합병정렬_병합(data, left, mid, right);
    }

    static void 합병정렬_병합(int [] data, int left, int mid, int right) {
        int left_helper = left;
        int right_helper = mid+1;
        int index_helper = 0;
        int [] sorted = new int [right - left + 1];
        while (left_helper <= mid || right_helper <= right) {
            if (left_helper > mid) {
                sorted[index_helper++] = data[right_helper++];
                continue;
            }
            else if (right_helper > right) {
                sorted[index_helper++] = data[left_helper++];
                continue;
            }
            if (data[left_helper] <= data[right_helper]) sorted[index_helper++] = data[left_helper++];
            else sorted[index_helper++] = data[right_helper++];
        }
        for (int i = left, j = 0; i <= right; i++, j++) {
            data[i] = sorted[j];
        }
    }
}

 

728x90
정렬 알고리즘 구현해 보기