오늘의 코딩#4

in kr •  3 years ago 

오늘은 이전에 풀던 좌표 정렬하기에 대한 풀이가 떠오르지 않아 다른 문제부터 풀려 했다.
그래서 선택한 문제가 단어 정렬 문제 였는데 같은 이유로 문제가 풀리지 않았다.

이 문제는 최대 20,000개의 단어를 입력 받아 길이가 짧은 단어부터, 길이가 같다면 사전 순으로 출력하는 문제이다.
20,000개 정도는 충분히 빠르게 연산할 거라 생각 했는데 생각보다 시간 복잡도가 컷나보다.

그래서 구글링을 좀 해봤는데 merge sort라는 방법이 있었다.
합병 정렬이라고 하는데 폰 노이만이 제안한 방법이라고 하더라.
인류 역사상 최고의 천재라는 폰 노이만이라는 이름을 보는 순간 신뢰도가 급 상승했다.

이 방법은 배열을 절반으로 나누는 것을 반복해 정렬하며 다시 합병하는 방식으로 진행된다.
그렇다 보니 상대적으로 시간 복잡도가 작은데 n log₂ n 이다
기존에 내가 사용했던 선택정렬 방식의 시간 복잡도가 n^2 임을 고려하면 확실히 작다.

이게 이렇게 보면 큰 차이가 안 나는 것처럼 보이는데 run-time을 보면 차이가 크다.
정수 60,000개를 정렬할때 선택정렬은 10.842초가 걸리고 병합정렬은 0.026초 정도 걸린다고 한다.

여튼 나는 이 문제를

#include <stdio.h>
#include <string.h>

void sort(char lst[][51], int left, int right, char sorted_lst[][51])
{
int mid = (right + left) / 2;
int i1 = left, i2 = mid + 1;
int i3 = left;
int num = right - left;

while (i1 <= mid && i2 <= right)
{
    if (strlen(lst[i1]) < strlen(lst[i2]))
        strcpy(sorted_lst[i3++], lst[i1++]);
    else if (strlen(lst[i1]) > strlen(lst[i2]))
        strcpy(sorted_lst[i3++], lst[i2++]);
    else
    {
        if (strcmp(lst[i1], lst[i2]) < 0)
            strcpy(sorted_lst[i3++], lst[i1++]);
        else
            strcpy(sorted_lst[i3++], lst[i2++]);
    }
}
while (i1 <= mid)
    strcpy(sorted_lst[i3++], lst[i1++]);
while (i2 <= right)
    strcpy(sorted_lst[i3++], lst[i2++]);
for (int i = 0; i <= num; i++)
{
    strcpy(lst[left + i], sorted_lst[left + i]);
}

}

void merge_sort(char lst[][51], int left, int right, char sorted_lst[][51])
{
int mid;

if (left < right)
{
    mid = (right + left) / 2;
    merge_sort(lst, left, mid, sorted_lst);
    merge_sort(lst, mid + 1, right, sorted_lst);
    sort(lst, left, right, sorted_lst);
}

}

int main(void)
{
int n, i;
char lst[20000][51] = {
0,
};
char sorted_lst[20000][51] = {
0,
};

scanf("%d", &n);
for (i = 0; i < n; i++)
    scanf("%s", lst[i]);
merge_sort(lst, 0, n - 1, sorted_lst);
for (i = 0; i < n; i++)
{
    while (i != n - 1 && strcmp(lst[i], lst[i + 1]) == 0)
        i++;
    printf("%s\n", lst[i]);
}
return (0);

}

이렇게 풀었다.
배열을 둘로 나눠 서로를 비교하며 더 작은 길이를 가지 것을 먼저 복사하는 행위를 재귀로 구현해 최소한의 크기(2개)부터 이 알고리즘이 시행되며 최종적으로는 전체를 정렬하도록 했다.

출력에서 같은게 있으면 출력하지 않도록 하라 해서 조건을 걸었다.
조건문에서 왼쪽을 먼저 판단하는 것을 이용해 segmentation fault를 방지했다.

내일은 이전에 못 풀었던 좌표 정렬하기 문제를 다시 풀어야겠다.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

반갑습니다~~
열심히 공부하는 모습이 부럽습니다~
화이팅입니다~

감사합니다!

반갑습니다..

전공과 다른 일을 하고 있어서 코딩은 이제 외계어로 보입니다...ㅎㅎㅎ

확실히 저도 파이썬 오랜만에 보면 기억이 안나더라구요!! 반갑습니다