본문 바로가기
<ALGORITHM>/NOTE

20210127(수)

by CodeGrimie 2021. 1. 27.

std::sort()

CPP 표준 라이브러리 <algorithm>에 정의되어 있는 함수.

기본적으로 오름차순이며 내림차순으로 지정할 수도 있다.

 

사용법

sort(v.begin(), v.end());
sort(v.begin(), v.end(), greater<int>());
sort(v.begin(), v.end(), compare());

▼ 예시 코드

#include <cstdio>
#include <cstdlib>
#include <algorithm>

void Print(int* arr)
{
    printf("arr[] : ");
    for (int i = 0; i < 10; i++)
        printf("%d ", arr[i]);
    printf("\n");
}

int main()
{
    int arr[10] = { 3,4,2,4,5,1,2,3,5,0 };
    Print(arr);
    std::sort(arr, arr + 10);
    Print(arr);

    system("pause");
    return (0);
}

std::vector

CPP 표준 라이브러리 <vector>에 정의되어 있는 기능이다.

배열에 비해 속도는 떨어지지만 메모리를 효율적으로 관리할 수 있는 장점이 있다.

링크드 리스트와 달리 vector는 연속적으로 메모리 블록을 사용한다.

원소가 추가되거나 삽입될 때 메모리 재할당이 발생하면서 메모리 부하가 생기는 단점도 존재한다.

 

▼ 예시 코드

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>

void Print(std::vector<int>& v)
{
    printf("vector : ");
    for (int i = 0; i < v.size(); i++)
        printf("%d ", v[i]);
    printf("\n");
}

int main()
{
    srand((int)time(NULL));

    std::vector<int> iv;
    int max = 10;

    for (int i = 0; i < max; i++)
    {
        iv.push_back(rand() % 10);
    }

    Print(iv);
    std::sort(iv.begin(), iv.end(), std::greater<int>());
    Print(iv);

    system("pause");
    return (0);
}

사용해보면 알겠지만 아주 편리하다.

그렇다고 언제나 배열 대신 vector를 사용하는 것이 좋은 것은 아니다.

 

같은 표준 라이브러리인 <array>가 정적 배열을 담당하고 <vector>는 동적 배열을 담당한다.

둘의 차이는 가변길이 여부일 뿐이라서 사용법 역시 크게 차이 나지 않는다.

 

<array>는 정적인 크기를 가진만큼 게임에서는 행렬 연산에 많이 사용된다.

편리성은 그대로인데다 vector의 단점인 메모리 부하가 발생하지 않는다.

 

▼ 응용 프로그램

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>
#include <windows.h>

void Print(std::vector<int>& v)
{
    for (unsigned int i = 0; i < v.size(); i++)
        printf("%d ", v[i]);
    printf("\n");
}

int main()
{
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
    WORD saved_attributes;

    GetConsoleScreenBufferInfo(hConsole, &consoleInfo);
    saved_attributes = consoleInfo.wAttributes;

    srand((int)time(NULL));
    int max = 10;

    std::vector<int> iv1;

    for (int i = 0; i < max; i++)
    {
        iv1.push_back(rand() % 10);
    }

    printf("> VECTOR 1[10]\n");
    printf("vector : ");
    SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE);
    Print(iv1);
    SetConsoleTextAttribute(hConsole, saved_attributes);
    std::sort(iv1.begin(), iv1.end(), std::greater<int>());
    printf("vector : ");
    SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE);
    Print(iv1);
    SetConsoleTextAttribute(hConsole, saved_attributes);
    printf("\n");

    std::vector<int> iv2;
    max = rand() % 10 + 1;
    for (int i = 0; i < max; i++)
    {
        iv2.push_back(rand() % 10);
    }

    printf("> VECTOR 2[%d]\n", max);
    printf("vector : ");
    SetConsoleTextAttribute(hConsole, FOREGROUND_RED);
    Print(iv2);
    SetConsoleTextAttribute(hConsole, saved_attributes);
    std::sort(iv2.begin(), iv2.end());
    printf("vector : ");
    SetConsoleTextAttribute(hConsole, FOREGROUND_RED);
    Print(iv2);
    SetConsoleTextAttribute(hConsole, saved_attributes);
    printf("\n");

    printf("> VECTOR CONCATENATED[%d]\n", 10 + max);
    iv1.insert(iv1.end(),iv2.begin(), iv2.end());

    printf("vector : ");
    SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE);
    for (unsigned int i = 0; i < iv1.size() - max; i++)
        printf("%d ", iv1[i]);
    SetConsoleTextAttribute(hConsole, saved_attributes);
    SetConsoleTextAttribute(hConsole, FOREGROUND_RED);
    for (unsigned int i = iv1.size() - max; i < iv1.size(); i++)
        printf("%d ", iv1[i]);
    printf("\n");
    SetConsoleTextAttribute(hConsole, saved_attributes);

    system("pause");
    return (0);
}

단순히 Vector를 하나 더 생성해서 이전 Vector에 추가해주는 프로그램이다.

구분이 잘되도록 <windows.h> 라이브러리를 사용해서 부분적으로 글자색을 변경했다.

erase()

CPP 표준 라이브러리 <algorithm>에 정의된 함수다.

특정 위치의 인자를 삭제하거나 특정 범위의 인자들을 삭제한다.

unique()

CPP 표준 라이브러리 <algorithm>에 정의된 함수다.

중복되지 않는 원소들을 앞에서부터 채워나가는 함수로 중복값의 첫번째 위치 주소값을 반환한다.

단, sort() 가 완료되어야 정상적으로 작동한다.

 

erase()와 함께 이용해서 중복 제거할 때 많이 응용된다.

 

▼ 예시 코드

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <string>
#include <vector>
#include <algorithm>

void Print(std::vector<std::string>& v)
{
    for (unsigned int i = 0; i < v.size(); i++)
        printf("%s ", v[i].c_str());
    printf("\n");
}

std::vector<std::string> sv;

int main()
{
    srand((int)time(NULL));

    int max = rand() % 5 + 1;

    for (int i = 0; i < 5 + max; i++)
    {
        char c[2] = { 65 + (rand() % 5), 0 };
        sv.push_back(c);
    }

    printf("> VECTOR ORIGIN\n");
    Print(sv);
    printf("\n");

    printf("> VECTOR SORTED\n");
    std::sort(sv.begin(), sv.end());
    Print(sv);
    printf("\n");

    printf("> VECTOR UNIQUED\n");
    auto buffer = std::unique(sv.begin(), sv.end());
    Print(sv);
    printf("\n");

    printf("> VECTOR ERASED\n");
    sv.erase(buffer, sv.end());
    Print(sv);
    printf("\n");

    system("pause");
    return (0);
}

응용 프로그램(로또 생성기)

▼ 전체 코드

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>

void Print(std::vector<int>& v)
{
    for (unsigned int i = 0; i < v.size(); i++)
        printf("%d ", v[i]);
    printf("\n");
}

int main()
{
    srand((int)time(NULL));
    std::vector<int> iv;

    for (; iv.size() <= 6;)
    {
        int number = rand() % 45 + 1;
        iv.push_back(number);

        auto buffer = std::unique(iv.begin(), iv.end());
        iv.erase(buffer, iv.end());
    }

    printf("> ROTTO NUMBER : ");
    Print(iv);
    system("pause");
    return (0);
}

단순히 겹치지 않는 숫자 6개를 생성하는 간단한 프로그램이다.

 

특이점으로 for문을 사용해서 무한 순환문을 돌고 있는데

그냥 for문을 이렇게도 쓸 수 있구나란 느낌으로 연습을 위해 사용한 것일 뿐이다.

find

CPP 표준 라이브러리 <algorithm>에 정의되어 있다.

데이터 중에 해당하는 값이 있는지 없는지 찾아서 주소값을 반환한다.

만약 찾는 값이 없다면 마지막 주소값을 반환한다.

 

▼ 사용 예시

std::find(v.begin(), v.end(), 3);

max_element / min_element

CPP 표준 라이브러리 <algorithm>에 정의되어 있다.

가장 크거나 작은 원소의 주소값을 반환한다.

 

▼ 사용 예시

printf("MAX : %d\n", *std::max_element(v.begin(), v.end()));

주소값을 반환하기 때문에 경우에 따라 Asterisk(*)를 붙여줘야 한다.

reverse

CPP 표준 라이브러리 <algorithm>에 정의되어 있다.

이름 그대로 원소들의 순서를 뒤집어준다.

 

▼ 사용 예시

std::reverse(v.begin(), v.end());

prev_permutation / next_permutation

CPP 표준 라이브러리 <algorithm>에 정의되어 있다.

오름차순 혹은 내림차순 순열을 구한다.

#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>

void Print(std::vector<int>& v)
{
    for (unsigned int i = 0; i < v.size(); i++)
        printf("%d  ", v[i]);
    printf("\n");
}

int main()
{
    std::vector<int> iv;

    std::vector<int> iv2 = {1,2,3,4};
    Print(iv2);
    while (std::next_permutation(iv2.begin(), iv2.end()))
    {
        Print(iv2);
    }

    system("pause");
    return (0);
}

순열은 말 그대로 순서를 나열해놓은 건데 배치 될 수 있는 경우의 수를 말한다.

예상컨데 카드 게임에서 덱의 카드를 무작위로 배열할 때 사용할 수 있지 않을까?

bitset

CPP 표준 라이브러리 <bitset>2진법을 이용한 문제에 유용하게 사용할 수 있다.

이걸 알았다면 비트 연산자 공부할 때 정말 편했을텐데..!

accumulate

CPP 표준 라이브러리 <numeric> 에 정의되어 있다.

배열의 모든 합을 구해주는 함수지만 실제로 사용하는 빈도 수는 매우 적다.

배열의 합이 현재 변수형의 최대값을 넘어가면 자동으로 변수형을 변경해주는 편의 기능이 추가되어있다.

Sleep

C 표준 라이브러리 <cstdlib> 에 정의되어 있다.

비주얼 스튜디오 2019에서는 <Windows.h>에 내장되어있는 Sleep()을 사용해야한다.

 

▼ 밀리초 단위로 작동한다.

Sleep(1000);

'<ALGORITHM> > NOTE' 카테고리의 다른 글

20210203(수)  (0) 2021.02.03
20210201(월)  (0) 2021.02.01
20210121(목)  (0) 2021.01.21
20210120(수)  (0) 2021.01.20
20210119(화)  (0) 2021.01.19

댓글