Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
/ CPP Public

Learning modern C++ concepts ( C++14, C++17, C++20 )

Notifications You must be signed in to change notification settings

doorcs/CPP

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

251 Commits

Repository files navigation

기억해야 할 내용들

  • getline() 사용 전에 cin 객체를 통한 입력을 사용했다면 cin.ignore() 꼭 해주기
    int N; cin >> N;
    cin.ignore()
    string s; getline(cin, s);
  • char 타입의 숫자를 정수형으로 변환
    char character = '1';
    int integer = character-'0'; // float, double, long, long long 모두 가능 (정수 값이 캐스팅되는것)
  • vector를 활용한 이차원 배열 만들기
    int COL = 세로길이(열), ROW = 가로길이(행)
    vector<vector<int>> brd(COL, vector<int>(ROW)); // `vector<T> vector(size, val=T())`를 중첩
  • fill()을 활용해 주어진 벡터나 배열을 초기화 (일부 수정도 가능)
    fill(iter, iter, val);
    // 이터레이터 두 개를 받아서, [inclusive, exclusive) 영역에 val을 채운다
    int arr[3] = {3, 6, 9}; // 새로 선언할 수 있다면 벡터를 쓰면 되는데, 문제에서 배열이 주어지는 경우가 있다
    fill(arr, arr+3, 0); // arr = {0, 0, 0}
    vector<int> vec(7, 3);
    fill(vec.begin()+2, vec.begin()+5, 6); // vec = {3, 3, 6, 6, 6, 3, 3}
  • stringstream 클래스와 getline() 함수를 활용한 split
    string str = "hello, world!";
    stringstream ss(str);
    while (getline(ss, str, ' ')) {
     cout << str << '\n'; // str 변수를 재활용
     // getline() 함수의 세번째 파라미터는 `반드시` char 타입이어야 함 (복잡한 delim 불가)
    }
  • split() 구현체
    vector<string> split(string str, string delim) {
     str.erase(str.find_last_not_of(" \t\n\r\f\v")+1); // 뒤쪽 공백 처리를 위한 right-trim
     vector<string> ret;
     size_t fr = 0, rr = str.find(delim); // 기능적 차이는 없지만 int를 쓰면 컴파일 warning
     while (rr != string::npos) {
     if (fr != rr) ret.push_back(str.substr(fr, rr - fr)); // delim이 연달아 나오는 케이스 대응
     fr = rr + delim.size();
     rr = str.find(delim, fr);
     }
     ret.push_back(str.substr(fr)); // delim이 하나도 없을 경우 전체를, 있다면 마지막 덩어리를 담아줌
     return ret;
    } // delimiter로 다양한 형태의 문자열을 사용할 수 있다
  • 비트마스킹 배열과 next_permutation()을 활용한 조합 찾기
    vector<int> num{1, 2, 3, 4, 5, 6, 7, 8, 9}, idx{0, 0, 0, 0, 0, 1, 1, 1, 1}; // 0 먼저 써야함!
    do {
     for (int i = 0; i < 9; i++)
     if (idx[i])
     cout << num[i] << ' '; // {6, 7, 8, 9}에서 {1, 2, 3, 4}까지의 모든 조합을 `역순`으로
     cout << '\n';
    } while (next_permutation(idx.begin(), idx.end())); 
  • 범위 기반 for문을 활용한 입출력 처리
    vector<int> vec1(3);
    for (int& it : vec1) cin >> it; // 입력 처리에는 `&`를 붙여야 함 (reference variable)
    for (int it : vec1) cout << it << '\n'; // for (auto it : vec1) cout << it << '\n';
    vector<pair<int, int>> vec2(5);
    for (auto& [a, b] : vec2) cin >> a >> b; // (C++17) structured binding - 앞에 auto 붙여주기!!
    for (const auto [a, b] : vec2) cout << a << ' ' << b << '\n'; // 출력은 `&`가 없어도 됨
  • <algorithm> 헤더 제공 함수들에서 initializer_list 클래스{} 활용
    int val1 = 9999, val2 = 3210, val3 = -2147483648;
    cout << min({val1, val2, val3}) << ' ' << max({val1, val2, val3});
    // cout << min(val1, min(val2, val3)) << ' ' << max(val1, max(val2, val3));
  • 비트 연산자를 활용한 효율적인 홀수 / 짝수 판별
    int even = 2, odd = 3;
    if (odd&1) cout << "odd"; // 홀수와 &1하면 결과값이 1, true (비트패턴은 마지막 비트만 1)
    if (!(even&1)) cout << "even"; // 짝수와 &1 하면 결과값이 0, false (비트패턴은 모든 비트가 0)
    // 짝수 판정은 반드시 두 번 이상의 연산이 필요하지만, 홀수 판정은 `&1`로 한 번의 연산에 처리할 수 있다

STL 컨테이너 사용법 정리

  • 컨테이너 공통:

    • .size() 메서드로 현재 담아두고 있는 요소의 수를 알 수 있음
    • .empty() 메서드로 현재 컨테이너가 비어있는지 알 수 있음
    • 컨테이너 생성 시점에 값들을 모두 알 수 있다면, initializer_list 생성자를 활용할 수 있음
  • 문자열 ( std::string )

    string str;
    // cin >> str; // cin을 통한 입력도 가능
    // cin.ignore() <<- 입력 처리에 cin 객체를 활용했다면, getline() 함수 사용 전에 cin.ignore() 필요
    getline(cin, str); // getline() 함수를 통해, 공백을 포함한 한 줄 입력을 string에 담을 수 있다
    // std::getline() 함수는 <string> 헤더에 있다!
    // 자르기 ( Substring )
    string sub = str.substr(start, count); // start 인덱스로부터 count개를 선택한 substring
    // str.substr(0, 3); <<- {0번째, 1번째, 2번째} 인덱스, 즉 {첫번째, 두번째, 세번째} 문자를 담아 return
    // 오른쪽 공백 제거 ( Right Trim )
    str.erase(str.find_last_not_of(" \t\n\r\f\v") + 1);
    // str.erase(find_last_not_of("0x20 | 0x09 | 0x0a | 0x0d | 0x0c | 0x0b")+1);
    // find_last_not_of()는 문자열이 모두 공백일 경우 string::npos를 반환하므로 +1을 해주면 0이 되는데,
    // str.erase(0)은 str.erase(0, string::npos)와 같고, 문자열을 모두 지운다
     
    // 왼쪽 공백 제거 ( Left Ttrim )
    str.erase(0, str.find_first_not_of(" \t\n\r\f\v"));
    // find_first_not_of()는 문자열이 모두 공백(whitespace character)일 경우 string::npos를 반환하므로
    // str.erase(0, string::npos)가 호출되어 문자열을 모두 지운다
  • 맵 ( std::map )

    map<T, U> mp; // map<T, U> mp{{key1, val1}, {key2, val2}};
    // key-value 매핑에 사용함. 내부적으로 pair<T, U>를 사용하며 key의 `operator<`를 적용해 오름차순으로 정렬함
    mp[key] = val; // 존재하지 않는 key에 접근하면 U의 기본 생성자가 호출되어 {key, val} 쌍을 map에 insert함
    mp[key]++; // map<int, int>일 경우, {key, 0} -> `++` -> 최종적으로 {key, 1}가 map에 insert됨
    .find(key); // find 메서드를 통해 특정 key의 존재 여부를 확인할 수 있음 - 존재하지 않을 경우 .end() 반환
    // .contains() 메서드가 더 직관적이지만, C++20 feature이므로 find 메서드에 익숙해지기
  • 해시맵 ( std::unordered_map )

    unordered_map<T, U> mp; // unordered_map<T, U> mp{{key1, val1}, {key2, val2}};
    // map과 비슷하지만 Hashing 방식으로 동작해 요소 접근의 시간복잡도가 O(1)
    // 단, key로 사용할 타입은 반드시 1. hash function, 2. equality check 두가지를 가지고 있어야 함
    // primitive types, string 정도만 key로 사용하는게 좋을 듯 (사용자 정의 객체를 key로 쓰려면 귀찮다)
  • 셋 ( std::set )

    set<T> s; // set<T> s{val1, val2, val3};
    // 포함 여부를 확인해야 할 때 시간복잡도를 줄일 수 있으며, 원소들의 uniqueness를 보장
    .insert(val); // insert 메서드를 통해 값을 추가하려고 `시도`할 수 있음 - 값이 이미 존재할 경우 무시됨
    .find(val); // find 메서드를 통해 특정 값의 존재 여부를 확인할 수 있음 - 존재하지 않을 경우 .end() 반환
  • 리스트 ( std::list )

    list<T> li; // list<T> li{val1, val2, val3};
    // [] 연산자를 지원하지 않아, 요소를 다룰 때 iterator를 사용해야 함
    // .begin() 이터레이터를 활용하는 방식이 가장 직관적임
    auto it = li.begin();
    cout << *it; // 첫번째 요소 참조
    for (int i = 0; i < N; i++) it++; // advance(it, N) 와 같다
    cout << *it; // N+1번째 요소 참조 (N이 2일 경우, 3번째 요소 참조)
    .insert(pos, val); // 이때 pos는 이터레이터. 새로 들어온 원소가 pos번째 원소가 됨
    .erase(pos); // 삭제된 원소 다음 원소를 가리키는 이터레이터를 return함. insert와 함께 사용할 수 있음
    li.insert(li.erase(it), val); // it자리에 원래 있던 원소를 삭제하고, val로 대체함
  • 벡터, 동적 배열 ( std::vector )

    vector<T> v; // vector<T> v{val1, val2, val3};
    // 동적 배열. 생성자를 호출 시 크기를 지정하지 않으면 기본 size와 capacity는 모두 0
    // push_back(), pop_back(), back() 세가지 연산으로 스택을 대체할 수 있음 (기능이 더 많아서 편리하다)
    .push_back(val); // 현재 요소들의 끝에 추가. stack.push() 대체 가능
    .pop_back(); // stack.pop() 대체 가능
    .back(); // stack.top() 대체 가능
    // .insert(pos, val) - insert 연산이 필요할 경우 vector 대신 list 쓰기
    vector<int> v(10);
    for (int& it : v) cin >> it; // for (auto& it : v) 도 가능
  • 덱 ( std::deque )

    deque<T> dq;
    .push_front(val);
    .pop_front();
    .push_back();
    .pop_back();
    // 뒤집는 연산이 필요할 때, 실제로 순서를 뒤집는 대신 반대로 순회하도록 할 수 있다
  • 큐 ( std::queue )

    queue<T> q;
    .front();
    .push(val);
    .pop();
  • 우선순위 큐 ( std::priority_queue )

    priority_queue<T> pq;
    .top(); // .front()가 아니라 .top()이다! top priority!!
    .push();
    .pop();

언젠가 고쳤던 좋지 않은 습관들

  • 줄바꿈이 필요할 땐 std::endl 대신 '\n' 사용
  • cin.tie(nullptr)->ios_base::sync_with_stdio(false); 처럼 쓰지 말고 분리하기
     cin.tie(nullptr);
     cout.tie(nullptr);
     ios_base::sync_with_stdio(false);
  • for, while 같은 제어문 키워드와 조건식 괄호 사이는 띄워주기
     for(;;) // bad
     for (;;) // good!
  • if, else if, else 구문 정렬 - closing brace on new line, else on same line
     if (cond1) {
     // 
     } else if (cond2) { // good! 
     //
     } else {
     //
     }

About

Learning modern C++ concepts ( C++14, C++17, C++20 )

Topics

Resources

Stars

Watchers

Forks

Languages

AltStyle によって変換されたページ (->オリジナル) /