Sorting Visualizer

Updated:

I. 의도

정렬알고리즘을 정리한지 한달도 지나지 않았는데 벌써 까먹었다. 마침 정렬과정을 눈으로 직접 확인할 수 있는 Sorting Visualizer를 만드는 유튜브를 보고 신기해서 북마크해놨던게 생각났다.

유튜브 링크 : Sorting Visualizer Tutorial (software engineering project)

위 같은 프로그램을 한번 직접 만들어보면 정렬알고리즘이 머릿속에 들어올 것 같았다. 나는 아직 프론트기술을 배우지 못했고, 따라서 동적 웹페이지를 구현할 수 없기 때문에 대신 콘솔로 구현하고자 했다.


II. 해설

main

#include <Windows.h> // system사용

int main()
{
    int select = 0;
    int length = 0;
    int arr[51];

    CursorView(false);
    system("mode con: cols=120 lines=55");


    while (true)
    {
        init(select, length);

        makeArr(arr, length);

        for (int i = 1; i <= length; i++)
        {
            draw(arr, i, length);
        }
       
        countDown(length);

        /*
        정렬 분기
        */
        switch (select)
        {
        case 1:
            bubbleSort(arr, length);
            break;
        case 2:
            selectSort(arr, length);
            break;
        case 3:
            insertSort(arr, length);
            break;
        case 4:
            mergeSort(arr, 1, length, length);
            break;
        case 5:
            heapSort(arr, length);
            break;
        case 6:
            quickSort(arr, 1, length, length);
            break;
        }

        gotoxy(0, length);
        std::cout << "정렬완료. 3초후 초기화면으로 돌아갑니다.";
        Sleep(3000);
    }
}

system("mode con: cols=120 lines=55") : 콘솔의 크기를 고정해준다.

select가 가지는 값에 따라 다른 정렬 분기로 들어간다.

CursorView

#include <Windows.h> // system 사용

// 커서숨기기
void CursorView(char show)
{
    HANDLE hConsole;
    CONSOLE_CURSOR_INFO ConsoleCursor;

    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    ConsoleCursor.bVisible = show;
    ConsoleCursor.dwSize = 1;

    SetConsoleCursorInfo(hConsole, &ConsoleCursor);
}

테트리스때에도 사용했던 함수이다.
커서 구조체를 선언해서 세팅해주는 방법이라고 한다.
단순히 커서를 숨기는 목적만 가지고 있었기 때문에 이부분은 널리 알려진 코드를 가져왔다.

gotoxy

#include <Windows.h>

void gotoxy(int x, int y)
{
    COORD pos = { x,y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

COORD는 단순히 SHORT형 x,y로 이루어진 구조체다.
아래의 함수를 통해 직접적으로 커서를 핸들링할 수 있게 된다.
마찬가지로 인터넷에서 쉽게 구할 수 있는 예제이다.

countDown

// 카운트다운 출력
void countDown(int length)
{
    int timer = 3;
    while (timer > 0)
    {
        gotoxy(0, length);
        std::cout << timer << "초 후 시작합니다." << '\n';
        Sleep(1000);
        timer--;
    }
    gotoxy(0, length);
    std::cout << "                                        \n";
}

가장하단에 시간이 지남에 따라 숫자가 줄어드는 문구를 출력해준다.

init

// 초기셋팅
void init(int& select, int& length)
{
    system("cls");
    gotoxy(0, 0);
    Sleep(10);

    std::cout <<
        "--------------------------------------\n" <<
        "| 1. BubbleSort                      |\n" <<
        "| 2. SelectSort                      |\n" <<
        "| 3. InsertSort                      |\n" <<
        "| 4. MergeSort                       |\n" <<
        "| 5. HeapSort                        |\n" <<
        "| 6. QuickSort                       |\n" <<
        "--------------------------------------\n";
    std::cout << "원하는 정렬을 선택해주세요.(1~6)" << '\n';
    std::cin >> select;
    while (select != 1 && select != 2 && select != 3 && select != 4 && select != 5 && select != 6)
    {
        std::cout << "올바른 번호를 입력해주세요.(1~6)" << '\n';
        std::cin >> select;
    }

    std::cout << "배열의 길이를 설정해주세요.(최솟값 : 10 | 최댓값 : 50)" << '\n';
    std::cin >> length;
    while (length < 10 || length > 50)
    {
        std::cout << "올바른 길이를 입력해주세요. (10~50)" << '\n';
        std::cin >> length;
    }
    system("cls");
}

초기 셋팅을 실시한다.
selectlength는 원하는 값을 받지 못하면 다시 받는다.
모든 셋팅이 이루어지면 화면을 모두 지워준다.

makeArr

#include <cstdlib> // srand, rand 사용
#include <ctime> // time 사용

// 랜덤배열 생성
void makeArr(int* arr, int length)
{
    int temp;
    srand((unsigned int)time(NULL));

    for (int i = 1; i <= length; i++)
    {
        arr[i] = i;
    }

    for (int i = 1; i <= length * 3; i++)
    {
        int x = rand() % length + 1;
        int y = rand() % length + 1;

        if (x != y)
        {
            temp = arr[x];
            arr[x] = arr[y];
            arr[y] = temp;
        }
    }
}

초기 배열을 랜덤하게 생성해준다. 매번 다른 배열을 생성하기 위해 시드에 time을 넣었다.

기본적으로 1 ~ length 까지 모두 인덱스로 초기화해주고 랜덤한 두 인덱스를 뽑아서 수를 교환해는 작업을 length * 3회 만큼 진행했다.

draw

void draw(int* arr, int idx, int length)
{
    std::string temp;

    temp = "";

    for (int k = 1; k <= arr[idx]; k++)
    {
        temp += "■";
    }
    for (int k = arr[idx] + 1; k <= length; k++)
    {
        temp += "  ";
    }

    gotoxy(0, idx - 1);
    std::cout << temp << '\n';
}

배열과 특정인덱스를 받아 해당 인덱스의 라인만 갱신해준다.

1 ~ length 전체를 갱신하는 것 보다 훨씬 효율적이다.

gotoxy를 이용해서 해당라인으로 이동한 뒤에 덮어씌우는 것이기 때문에 뒤에 length까지 모두 지워지도록 빈칸을 더했다.

Sort

6가지의 Sorting Algorithm을 각각 구현했다.
따로 포스팅한 바가 있기 때문에 생략한다.

정렬 알고리즘 보러가기




III. 결과

BubbleSort

bubblesort

SelectSort

selectsort

InsertSort

insertsort

MergeSort

mergesort

HeapSort

heapsort

QuickSort

quicksort

VI. 마무리

단순히 글과 그림만으로 이해하는 것 보다 프로그램을 통해서 만들어보고 실시간으로 과정을 확인하는 것이 훨씬 이해에 도움이 되었다.

누군가가 정렬 알고리즘에 대해 공부하려 하거든 꼭 내 프로그램으로 공부할 것을 권장하고 싶을 정도이다.

github에서 코드 보기

Leave a comment