본문 바로가기

알고리즘 문제풀이/코테 꿀팁

(C++) sort 커스터마이징 , STL vector 멤버 함수, 문자열 find

반응형

1. sort 함수 커스터마이징

bool comp(const type& A, const type& B);

sort(vec.begin(), vec.end(), comp);
sort(ary, ary + n, comp); // n은 ary 배열의 크기

 

sort 함수는 <algorithm> 라이브러리에 있는 메소드로 벡터나 배열을 정렬할때 사용된다. 기본적인 사용 방법은 위와 같다. 여기서 comp 함수를 따로 정의해주면 정렬을 사용자 입맛대로 할 수 있다. 

 

comp 함수는 두 개의 매개변수를 가지는데, 타입은 string, struct, class, int 등 모두 사용 가능하다. 정렬되는 순서는 true가 되는 규칙을 따른다. 사실 이게 끝이다. 

 

 

예를 들어보자. 매개변수 타입이 string이라고 가정해보자. 만약에 아래와 같다면 정렬 규칙은 어떻게 될까?

 

bool comp(const string& a, const string& b){
    return a.length() < b.length();
}

 

참이 되는 경우는 a의 길이가 b의 길이보다 작을 때다. 따라서 정렬 규칙은 '문자열의 길이가 작은 순서로 오름차순'이 된다. 그러면 여기에 '알파벳 순서가 작은 순서대로 정렬' 규칙을 추가해보자. 최종적으로 만들고 싶은 규칙은 '문자열 길이가 작은 순서로 오름차순(우선순위), 알파벳 순서가 작은 순서대로 정렬(후순위)' 이다. 직접 해보기를... 사실 이 규칙은 이 문제의 정답 코드이기도 하다. 정답은 더보기란을 클릭하면 된다. 

 

더보기
bool comp(const string& a, const string& b){
    if(a.length() == b.length())
        return a < b;
    return a.length() < b.length();
}

 

2. STL vector 멤버 함수

sort(p, q) : p~q 내에 있는 원소들을 오름차순으로 정렬. 아까 설명했듯이 커스터마이징 가능
random_shuffle(p, q) : p~q 내에 있는 원소들을 무작위로 재배치
reverse(p, q) : p~q 내에 있는 원소들의 순서를 역순으로 바꾼다
find(p, q, e) : p~q 내에서 e와 같은 첫 번쨰 원소를 가르키는 반복자를 반환. e가 없으면 q를 반환
min_element(p, q) : p~q 내에 있는 원소 중 최소값을 가리키는 반복자 반환
max_element(p, q) : p~q 내에 있는 원소 중 최대값을 가지리키는 반복자 반환

 

'반복자를 반환' 함에 유의하자. 따라서 출력할 때는 '*'를 붙여줘야 한다. 사용법에 별다른 특이사항은 없으므로 예시 코드는 생략한다. 

 

참고로... 벡터, 리스트, 데크를 시퀀스 컨테이너라고 부르는데 이들끼리는 서로 복사가 굉장히 간편하다. 배열은 STL 반복자가 아니지만, 포인터 연산에 의해 반복자처럼 실행될 수 있다. 아래 코드를 참고하자.

 

int A[] = { 5, 6, 3, 8, 1}; 

vector<int> V(A, A + 5);
list<int> L(A, A + 5);
deque<int> D(V.begin(), V.end());

 

3. 문자열 find

문자열에서 찾고 싶은 문자의 인덱스를 반환해주는 함수다. 사용법은 아래와 같다. 

 

// str의 첮 번째 문자부터 탐색. search 시작 위치 반환
str.find(search); 

// str의 start번째 문자부터 탐색. search 시작 위치 반환
str.find(search, start);

// 찾지 못하면 string::npos 반환

 

 

코드가 아래와 같을때 결과를 예상해보자.

 

string str = "a_c_d";
string search = "_";

cout << str.find(search) << '\n'; // 1 반환

cout << str.find(search, 2) << '\n'; // 3 반환

if(string::npos == str.find('A'))
    cout << "not found" << '\n'; // 정상 출력

 

 

이왕 한김에 문자열을 특정 토큰을 기준으로 분리하는 함수를 짜보자. 이를 구현하기 위해 substr 함수를 알아야 한다. substr 함수의 사용법은 아래와 같다. 

 

// n번째 인덱스부터 끝까지 자름
str.substr(n);

// n번째 인덱스부터 m개의 문자 자름
str.substr(n, m);

 

 

코드가 아래와 같을때 결과를 예상해보자. 

 

string str = "a_c_d";
string search = "_";

cout << str.substr(1) << endl; // _c_d 출력
cout << str.substr(0, 2) << endl; // a_ 출력
cout << str.substr(1, string::npos) << endl; // _c_d 출력

 

아마 마지막 줄이 예상과 달랐을 것이다. substr은 두 번째 인자값이 문자열의 크기를 넘어가면 그냥 '문자열의 끝까지'로 인식한다. string::npos은 쓰레기값으로 아주 큰 임의의 숫자라고 생각하면 된다. 따라서 substr(n, string::npos)는 n번째 인덱스부터 끝까지 잘라주는 것으로 이해하면 된다. 

 

우리가 구현하고자 함수는 다음과 같다. 

 

vector<string> split(string input, string token);

input을 token을 기준으로 분리

split("my[]name[]is[]chan", "[]") 의 결과는 {"my", "name", "is", "chan"}

 

설명은 주석을 참고하자!!

 

vector<string> split(string input, string token){
    vector<string> vars;
    
    int pre = 0; // pre는 시작 인덱스가 된다
    int cur = input.find(token); // cur는 토큰의 인덱스
    
    while (cur != string::npos) {
        
        // pre번째 인덱스부터 (cur - pre)개 자른다
        vars.push_back(input.substr(pre, cur - pre));
        
        // 다음 시작점은 토큰의 다음 인덱스
        pre = cur + token.size();
        
        // 다음 토큰의 위치는 시작점 다음부터 탐색
        cur = input.find(token, pre);
    }
    
    // 남은 부분 잘라준다.
    vars.push_back(input.substr(pre, cur - pre));
    
    return vars;
}

 

반응형