※ 유클리드 호제법 (Euclidean Algorithm)

 

 

※ 등수 구하기

점수가 주어졌을 때, 등수를 구한다.

 

 

 

 

 

 

 

 

 

 

※ 방향 탐색 (knight의 이동)

 § 4방향 탐색, 8방향 탐색

 

 

 § Knight의 방향탐색

 

 

 

https://www.acmicpc.net/problem/7562

 

7562번: 나이트의 이동

체스판 위에 한 나이트가 놓여져 있다. 나이트가 한 번에 이동할 수 있는 칸은 아래 그림에 나와있다. 나이트가 이동하려고 하는 칸이 주어진다. 나이트는 몇 번 움직이면 이 칸으로 이동할 수

www.acmicpc.net

https://www.acmicpc.net/problem/16959

 

16959번: 체스판 여행 1

크기가 N×N인 체스판이 있고, 체스판의 각 칸에는 1부터 N2까지의 정수가 한 번씩 적혀있다. 지학이는 이 체스판을 이용해서 재미있는 게임을 해보려고 한다. 지학이가 가지고 있는 말은 나이트,

www.acmicpc.net

https://www.acmicpc.net/problem/16952

 

16952번: 체스판 여행 2

크기가 N×N인 체스판이 있고, 체스판의 각 칸에는 1부터 N2까지의 정수가 한 번씩 적혀있다. 지학이는 이 체스판을 이용해서 재미있는 게임을 해보려고 한다. 지학이가 가지고 있는 말은 나이트,

www.acmicpc.net

 

 

 

 

 

※ 이차원 배열을 이용한 부분합

 

 

 

 

 

 

 

 

 

 

- Euclidean Algorithm(유클리드 호제법)
https://www.acmicpc.net/problemset?sort=ac_desc&algo=26

- 등수 구하기

- 방향 탐색(4방향, 8방향, knight)
https://www.acmicpc.net/problem/7562

- 이차원 배열의 부분합
- 이차원 배열의 부분합(feat. 포함-배제의 원리)
https://www.acmicpc.net/problemset?sort=ac_desc&algo=139

 

※ 약수, 배수 (최대공약수, 최소공배수)

cf. 최대공약수, 최소공배수를 재귀함수로 해결하기. https://chan4im.tistory.com/58

 

[Baekjoon/백준] 13241, 5347번: [Recursion] (C/C++) ★★☆

※ 이번 문제에서 알게된 점 § 재귀함수로 구현하는 gcd, lcm 함수 // 최대공약수 auto gcd(long long A, long long B){ if (B == 0) return A; else return gcd(B, A%B); } // 최소공배수 auto lcm (long long A, long long B){ return A*B

chan4im.tistory.com

 

 

※ 최소, 최대, 최빈값 찾기

§ 최소, 최대값을 찾기 위한 방법: https://chan4im.tistory.com/48

 

this.algorithm(2). merge() 함수, copy() max(), min() 함수 ★★★★★

※ vector를 이용한 합병정렬 구현 #include #include #include using namespace std; int main() { vector v1(2); vector v2(3); for (int i = 0; i < v1.size(); i++){ cin >> v1[i]; } for (int i = 0; i < v2.size(); i++){ cin >> v2[i]; } vector v3; v3.res

chan4im.tistory.com

 

 

§ 최빈값 찾는 알고리즘

 

 

 

※ palindrome (회문) 

https://www.acmicpc.net/problem/17609

 

17609번: 회문

각 문자열이 회문인지, 유사 회문인지, 둘 모두 해당되지 않는지를 판단하여 회문이면 0, 유사 회문이면 1, 둘 모두 아니면 2를 순서대로 한 줄에 하나씩 출력한다.

www.acmicpc.net

 

 

 

 

 

 

※ 일정구간 연속값 찾기

 

 

 

※ 소수판별과 에라토스테네스의 체

 

 

 

 

 

 

 

※ 부분합 (누적합)

 

 

 

 

 

 

 

 

 

 

 

 

- 약수, 배수, 최대공약수, 최소공배수

- 소문자->대문자 , 완전수

- Palindrome, 최대,최소,최빈값
https://www.acmicpc.net/problem/17609

- 소수판별, 에라토스테네스의 체
https://www.acmicpc.net/problem/1929

- 부분합
https://www.acmicpc.net/problemset?sort=ac_desc&algo=139

※<cstdlib>

 abort() : 프로그램을 "비정상적으로 종료"

 exit(n) : 값을 n으로 프로그램을 종료 (n==0이면 성공적인 종료)

 d=rand() : d는 [0 : RAND_MAX] 범위에 있는 의사 난수다.

 

 

 

※<cmath>

 

§ x의 y승을 구하려면 원래는 다음과 같이 구현해야한다.

#include <iostream>
using namespace std;

int main(){
    int x, y;   cin >> x >> y;
    int result = 1;
    for (int i = 0; i < y; i++) 
        result *= x;
    cout << result;
}

 

§ 하지만 <cmath>의 내장함수인 exp2나 pow함수를 이용하면 매우 짧은 코드로 답을 낼 수 있어 유용하다.

#include <iostream>
#include <cmath>
using namespace std;

int main(){
    int x, y;   cin >> x >> y;
    cout << pow(x,y);
}

 

#include <iostream>
#include <cmath>
using namespace std;

int main(){  // x값 2 한정
    int y;   cin >> y;
    cout << exp2(y);
}

※ unique 함수

- 벡터에서 중복원소를 제거할 때, sort, erase, unique 기능을 적절히 활용하여 제거할 수 있기에

 unique 함수의 사용은 익혀야 할 필요성이 두드러진다 생각한다. 

- 또한 int가 아닌 char형도 가능하다는 점에서 대단히 유용하다.

 

cf. 만약, sort하지말고 중복원소를 제거하라면 set + assign함수를 사용한다.

(set은 중복 원소를 허용하지 않는 컨테이너기 때문이다.)

https://scarlettb.tistory.com/70

[백준 13915번: https://www.acmicpc.net/problem/13915]

 

13915번: 현수의 열기구 교실

현수는 열기구 여름특강의 강사다. 현수는 매우 성실해서 모든 수강생들의 열기구 비행을 기록하고있다. 매 비행 이후, 현수는 그 비행에 참석한 수강생들의 기록을 리스트에 추가한다. 리스트

www.acmicpc.net

 

 

§ unique의 원리

- "정렬된" 원소에 대해 vector의 제일 뒷부분으로 쓰레기값으로 보내버린다.

- 따라서 "정렬"되어야 하므로 sort를 사용해야한다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int N;  cin >> N;
    vector<int> v;
    for(int i = 0; i < N; i++){
        int num;    cin >> num;
        v.push_back(num);
    }

    sort(v.begin(), v.end());

    unique(v.begin(), v.end());

    for(auto x:v)
        cout << x << " ";
}

 

input >>  1 4 3 2 2 3 1 5 3 5 4
output << 1 2 3 4 5 3 3 4 5 5

앞에 1 2 3 4 5가 정렬된 이후 뒤 숫자는 아무렇게나 쓰레기값이 들어간 것을 알 수 있다.

 

 

 

 

§  중복원소제거 정렬

따라서 정렬 후 erase와 unique로 삭제할 수 있다.

다음과 같이 작성하면 된다.

sort(v.begin(), v.end());
v.erase( unique(v.begin(), v.end()), v.end() );

 

 

 

 

 

 

 

 

 

 

※ 중복된 원소 제거 => sort, erase(unique())

 

[백준 10867번: https://www.acmicpc.net/problem/10867]

 

10867번: 중복 빼고 정렬하기

첫째 줄에 수의 개수 N (1 ≤ N ≤ 100,000)이 주어진다. 둘째에는 숫자가 주어진다. 이 수는 절댓값이 1,000보다 작거나 같은 정수이다.

www.acmicpc.net

 

[숫자벡터에 대한 중복 원소 제거]

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int N;  cin >> N;
    vector<int> v;
    for(int i = 0; i < N; i++){
        int num;    cin >> num;
        v.push_back(num);
    }

    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());

    for(auto x:v)
        cout << x << " ";
}

 

 

 

[문자벡터에 대한 중복 원소 제거]

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<char> s;
    for (int i = 0; i < 10; i++) {
        char c;     cin >> c;
        s.push_back(c);
    }
    sort(s.begin(), s.end());
    s.erase(unique(s.begin(), s.end()), s.end());

    for(auto x:s)
        cout << x << " ";
}

 

※ ios_base::sync_with_stdio(bool sync);

bool sync == false: C 의 stdio.h와 C++의 iostream의 동기화를 끊는다.

bool sync == true: 함수 호출하기 전 이전의 동기화 상태

 

[sync : true]

- 모든 stream들은 동기화가 되어있으며 동기화된 stream들이 자신의 buffer대신 C stream buffer를 사용

stream buffer: data를 보내거나 받기 전, 임시로 저장되는 곳으로

바로 사용하지 않고 버퍼에서 보관, 어느정도 모이면 출력하는 방식으로 작업함.

 

- 동기화된 C++ stream들은 thread-safe, 안정성을 보장한다.

- 따라서 입출력 순서가 정해져있어서 race condition이 발생하지 않는다. (race condition: https://chan4im.tistory.com/36)

 

this->OS.code(5)

다수의 thread가 concurrent하게 실행 => thread 충돌문제 발생이 가능하다. cf. single thread의 경우, process 충돌이라고도 부른다. - race condition: 2개 이상의 process가 같은 메모리를 거의 동시에 접근(access)할

chan4im.tistory.com

 

[sync : false]

- 동기화를 끊게되면 C++ stream은 자신들의 독립적인 buffer를 갖게된다.

- 따라서 입출력 객체를 섞어 사용하면 출력순서를 보장할 수 없어 오답, race condition 발생 가능성이 있다.

- multi-thread의 경우, Thread-unsafe해져서 예상하지 못한 값이 나올 수도 있다.

 

※ 입출력 속도비교

[scanf, printf, \n]  >>>>>>>> [cin, cout, endl]

 

 

 

 

§  ios_base::sync_with_stdio() 함수

먼저 C++의 <iostream>은 C의 <stdio.h>와 다르다. 

C++의 입출력 작업 시, C의 입출력과 동기화 되도록 설계되어 상당히 느린 입출력과정을 겪는다.

추가적으로 endl도 출력문자 출력+출력buffer를 함께 비워 시간이 많이 걸려 \n사용을 권장한다.

이때 말하는 "동기화"를 뜻하는 코드가 ios_base::sync_with_stdio이고, 이 동기화를 풀어주는 코드이다.

따라서 동기화가 풀어진다면?  => 당연히 속도를 올릴 수 있다!

ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

 

큰 힘에는 큰 책임이 따른다고, 이런 ios_base::sync_with_stdio에도 치명적인 단점이 있다.

 

1. 그건 바로 싱글 쓰레드 (single thread) 환경은 괜찮지만, 멀티 쓰레드 (Multi Thread)환경에서는 출력순서가 어그러진다.

즉, 멀티쓰레드 환경에서의 출력순서가 보장될 수 없다는 것이다! (race condition 발생 가능)

cf-1) 코딩테스트에서는 싱글쓰레드만 사용하기에 사용해도 무방하다.

cf-2) 다만 실무에서는 ios_base::sync_with_stdio를 쓰기보단, 속도를 올리기 위해 C입출력 방식을 권장한다.

 

 

2. 버퍼가 분리되었기에 cin과 scanf, gets, getchar 등의 C문법 (당연히 출력코드도 동일)을 같이 사용할 수 없다!

 

cf-2) 싱글, 멀티쓰레드란? https://chan4im.tistory.com/35

 

this->OS.code(4)

exit() system call, 처리불가능한 signal, CPU err, 부모 process의 명령과 같은 상황에서 process termination이 발생하며 아직 process 상태에 존재한다. (process에 존재하지만 실행에 필요한 컴퓨터 자원들을 proces

chan4im.tistory.com

 

 

 

§  cin.tie(NULL)  /  cout.tie(NULL) 함수

[정의]: istream, ostream 즉, stream을 untie 하여 자동으로 입출력 버퍼를 비우지 않게 함

cin과 cout간의 tie를 끊어주는, 즉 다른 입출력이 온다면 기존의 입출력을 비워주도록 하는 것이다.

이 tie를 끊어줌으로써 시간을 많이 절감할 수 있다. (cin을 cout으로부터 풀어줌.)

기본적으로 cout의 출력은 buffer가 가득차거나 수동적으로 flush되기 전까진 출력되지 않는다.

 

[flush]: 현재 buffer에 저장되있는 내용클라이언트로 전송buffer를 비우는 것을 말함.

 

- stream을 tie하면 다른 stream에서 입출력 요청이 오기 전stream을 먼저 flush 시킨다.

 

- stream을 untie하면 output이 flush되지 않은 채로 user에게 input을 요구한다.

- untie를 해주었다면, cin으로 입력받기 전, 출력하고 싶다면 수동적으로 cout을 flush 해줘야 한다.

 

[예시]

왼쪽그림에서 ios_base::sync_with_stdio(0);을 지워도 console창은 하게 뜬다.

왼쪽을 보면 cout으로 "입력"이란 문구가 출력된 후 cin이 나오는 것을 알 수 있고, 이는 익숙한 방식이다.

하지만 우측은 입력 후 출력이 모두 동시에 되는 것을 알 수 있다.

우리가 tie를 끊어서 입력 전에 출력관련 문구가 아무리 입력보다 먼저 적혀있었더라도 출력이 되지 않는다.

만약 입력전에 출력되게 하고 싶다면 cout의  buffer를 수동으로 비워줘야 한다.

※ vector를 이용한 합병정렬 구현

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> v1(2);
    vector<int> v2(3);

    for (int i = 0; i < v1.size(); i++){
        cin >> v1[i];
    }
    for (int i = 0; i < v2.size(); i++){
        cin >> v2[i];
    }

    vector<int> v3;

    v3.reserve(v1.size() + v2.size());
    v3.insert(v3.end(), v1.begin(), v1.end());
    v3.insert(v3.end(), v2.begin(), v2.end());

    sort(v3.begin(), v3.end());

    for (const auto& x:v3) {
        cout << x << " ";
    }
}

 

v3.reserve(v1.size() + v2.size());
v3.insert(v3.end(), v1.begin(), v1.end());
v3.insert(v3.end(), v2.begin(), v2.end());
v3.resize(v1.size() + v2.size());
v3.insert(v3.end(), v1.begin(), v1.end());
v3.insert(v3.end(), v2.begin(), v2.end());

위와 아래의 차이점은 뭘까?

즉, reserve와 resize의 차이점은 무엇일까?

 

 

§ reserve() 와 resize() 의 차이

capacity: 미리 할당해놓은 배열공간

size: 배열에 들어있는 원소의 수

 

대부분의 컨테이너 STL 자료구조들은 일정 크기를 할당(capacity)한 후 

size가 capacity를 넘으면 2배정도의 크기를 늘려 이동하는 방식으로 구현되어 있다.

 

§ reserve(N)

- vector의 capacity를 N으로 설정하는 것.

- N이 현재 capacity보다 클 때만 작동, 작으면 아무 일도 발생X

- N이 현재 capacity보다 크다면 모든 원소 reference와 iterator가 전부 무효화(invalidate)된다.

 

§ resize(N)   /   resize(N, value)

- size > N인 경우, 원소의 개수를 줄인다.

- size < N인 경우, 입력된 value가 없으면 default값인 0으로 할당한다. 있다면 value로 할당.

  그 후, size가 N이 되도록 늘린다.

 

 

 

 

 

 

 

※ merge()와 sort()를 이용한 합병정렬 구현

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> v1;
    vector<int> v2;

    for (int i = 0; i < 3; i++) {
        int num;    cin >> num;
        v1.push_back(num);
    }
    for (int i = 0; i < 3; i++) {
        int num;    cin >> num;
        v2.push_back(num);
    }
    vector<int> v3;

    merge(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(v3));

    sort(v3.begin(), v3.end());

    for (const auto& x:v3) {
        cout << x << " ";
    }
}

 

 

 

§ merge() 함수의 원리

merge( first1, last1, first2, last2, result );

result = first1 [first2, last2] last1 형식으로 결과값이 result에 누적된다. 

예를 들어 다음과 같은 입력이 주어질 때, 다음과 같이 merge된다.

[v1]: 1 200 3 2
[v2]: 45 5 2 23 31
[v3]: 1 45 5 2 23 31 200 3 2

즉, 아래와 같이 내부적으로 되어있다는 것을 알 수 있다.

[v1]: 1 200 3 2
[v2]: [45 5 2 23 31]
[v3]: 1 [45 5 2 23 31] 200 3 2

 

 

§ back_inserter() 함수의 원리와 copy() 함수

벡터의 맨 끝에 값을 삽입하는 "iterator"의 일종이다.

예를 들어 다음과 같이 작동한다.

std::vector<int> v1, v2;
// v1 : 1, 3, 5 , v2 : 10, 30, 50

std::copy(v1.begin(), v1.end(), back_inserter(v2));
v2 : 10, 30, 50, 1, 3, 5 //v2의 맨 끝부터 차례대로 v1의 값들이 복사되어 삽입 된다.

std::copy(v1.begin(), v1.end(), front_inserter(v2));
v2 : 5, 3, 1, 10, 30, 50 //v2의 맨 앞으로 v1의 값들이 복사되어 삽입 된다.

 

 

 

 

 

https://www.acmicpc.net/problem/11728

 

11728번: 배열 합치기

첫째 줄에 배열 A의 크기 N, 배열 B의 크기 M이 주어진다. (1 ≤ N, M ≤ 1,000,000) 둘째 줄에는 배열 A의 내용이, 셋째 줄에는 배열 B의 내용이 주어진다. 배열에 들어있는 수는 절댓값이 109보다 작거

www.acmicpc.net

 

 

 

 

 

 

 

 

 

 

※ max(), min() 2개를 이용한 방법

 

최대 최소는 값 비교를 해 결정하는 것이다.

이런 값 비교는 많은 상황에서 쓸모가 있다.

 

따라서 우리는 이에 대해 가장 대표적인 예제로 vector와 pair로 구현해볼 것이다.

 

The C++ Programmin Lauguage

 

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> v(5);

int main() {
    int num;
    for (auto x:v) {
        cin >> num;
        v.push_back(num);
    }
    int M = 0;
    int m = 1000000000;
    for (int i = 0; i < v.size(); i++) {
        M = max(v[i], M);
        m = min(v[i], m);
    }
    cout << "최댓값: " << M << "최솟값: " << m;
}

 

여기서 가장 핵심이 되는 키워드는 for문 안에 있는 max, min 함수이다.

M = max(v[i], M);
m = min(v[i], m);

사실 우리는 이 구문에 대해 많이 봐왔는데 if문으로 표현할 수 있다.

if(M < v[i]){
    M = v[i];
}
if(m > v[i]){
    m = v[i];
}

 

 

 

※ minmax_element() 함수를 이용한 방법

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> v;

int main() {
    int num;
    for (int i = 0; i < 5; i++) {
        cin >> num;
        v.push_back(num);
    }

    auto it = minmax_element(v.begin(), v.end());
    cout << "최솟값: " << *it.first << " " << "최댓값" << *it.second << endl;
}

 

 

코드의 엄청난 압축이 가능하니 되도록 max, min, minmax함수를 써보는 것을 추천한다.

(cf. maxmin은 없다.)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

C++에서 가장 번거로운것 중 하나는 문자열 처리이다.

 

Tip!

1. getline은 앞뒤 개행문자까지 다 읽어온다.

string str;
getline(cin, str);

2. 문자 "0"를 int로 바꾸려면 '0'을 빼준다.

3. str.find(str2)를 했는데 못찾을 때, -1을 반환한다 생각해도 된다! (사실은 string::npos를 반환하지만)

4. str.find(str2, index)는 index 부터 탐색한다.

5. str.erase(index, size)는 삭제를 시작할 index와 크기이다.

 

 

※ 문자열 자르기

Case 1) string 클래스 사용할 때

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Hello, world, Korea";
    size_t prev = 0;
    size_t curr = str.find(','); //못찾으면 npos 반환
    
    while (curr != string::npos) {
        string substring = str.substr(prev, curr - prev);
        cout << substring << ' ';
        prev = curr + 1;
        curr = str.find(',', prev);
    }
    cout << str.substr(prev, curr - prev);
}

 

Case 2) sstream 클래스 이용할 때

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int main() {
    string str = "Hello world and Korea";
    istringstream iss(str);
    string token;
    
    while (getline(iss, token, " ")){
        cout << token << endl;
    }
}

 

 

Case 3) 특정 문자열 찾기

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "hello my name is V2LLAIN";
    string word = "V2";

    int pos = str.find(word);

    while (pos != string::npos) {
        cout << str.substr(pos, word.size()) << endl;
        pos = str.find(word, pos+word.size());
    }
}

 

 

출처: https://velog.io/@siyeonkm/cpp-%EC%BD%94%ED%85%8C%EC%97%90%EC%84%9C-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94%EA%B2%83%EB%93%A4

 

 

 

 

 

 

※ 가장 많이 출제되는 코딩테스트 유형들

1. DFS / BFS

2. 문자열

3. 구현

4. DP

https://velog.io/@pppp0722/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%AC%B8%EC%A0%9C-%EC%9C%A0%ED%98%95-%EC%A0%95%EB%A6%AC

 

 

 

 

 

 

 

 

 

 

 

 

 

 

vector / pair / stack ,queue, deque, priority queue / map / set  / algorithm / iterator / bitset

The C++ Programming Language 4th.Edition

 

vector(std::vector) _가변배열 / 가장 기본이 되는 컨테이너 (★)

 

#include <vector>
using namespace std;

vector<자료형> 변수명(숫자)    //숫자만큼 벡터 생성 후 0으로 초기화
vector<자료형> 변수명(숫자, 변수1);   //숫자만큼 벡터 생성 후 변수1으로 모든 원소 초기화
vector<자료형> 변수명{숫자, 변수1, 변수2, 변수3, ...};    // 벡터 생성 후 오른쪽 변수 값으로 초기화
vector<자료형> 변수명[]={ {변수1, 변수2}, {변수3, 변수4}, ...}   //2차원 벡터생성 (열은 고정, 행 가변)
vector<vector <자료형>> 변수명   //2차원 벡터생성 (열, 행 가변)

ex);
vector<int> vec1; // 크기가 0인 벡터 선언
vector<int> vec2(10); // 크기가 10인 벡터 선언
vector<int> vec3(10, 3); // 크기가 10이고 모든 원소가 3으로 초기화된 벡터
vector<int> vec4 = { 1,2,3,4,5 }; // 크기가 지정한 초기값으로 이루어진 벡터
vector<int> vec5[] = { {1,2},{3,4} }; // 벡터 배열 생성(행은 가변인지만, 열은 고정)
vector<vector<int>> vec6; // 2차원 벡터 생성(행과 열 모두 가변)

 

※ vector 요소 삽입, 제거, 변경

#include <vector>
using namespace std;

int main() {
    vector<int> vec; // 크기가 0인 벡터 선언

    vec.push_back(10);
    vec.push_back(20); // vec = {10, 20}

    vec.insert(vec.begin() + 1, 100);  // vec = {10, 100, 20}

    vec.pop_back();       // vec = {10,100}

    vec.emplace_back(1);   // vec = {10, 100, 1}
    vec.emplace_back(2);   // vec = {10, 100, 1, 2}
    vec.emplace(vec.begin() + 2, -50); // vec = {10, 100, -50, 1, 2}

    vec.erase(vec.begin() + 1);    // vec = {1, -50, 1, 2}
    vec.resize(6); // vec = {1, -50, 1, 2, 0, 0}
    vec.clear();   // vec = empty()
}

 

※ vector의 index 접근

※ vec.at(i)와 vec.[i]의 차이점

- at은 범위를 검사하여 범위 밖의 요소에 접근 시 예외처리를 발생시킨다. (std::out_of_range)

- [ ]은 범위검사를 하지 않으며 예외처리를 발생시키지 않는다. (범위 밖 요소에 접근하면 디버깅 발생)

 

vector는 효율에 중점을 두기에 보통 [ ]를 권장한다.

 

※ vector의 크기 size, capacity

- size: vector의 크기, 즉 벡터에 실제로 저장된 원소의 개수를 뜻한다.

- capacity: vector의 용량, 즉 벡터의 최대 할당 크기를 뜻한다.

 

만약 벡터의 크기가 용량을 초과한다면 재할당이 발생한다. (기존 값 새 메모리에 복사 후 파괴)

if (size > capacity) {
    reallocate <- 모든 값 새 메모리에 복사 후 기존 벡터 파괴
}

 

Problem 1. 새 메모리의 복사과정에서 복사생성자가 발생해 성능이 저하될 수 있다.

Solution 1. reserve()라는 함수를 사용해서 벡터의 용량을 충분히 크게 생성할 수 있다.

 

Problem 2. reserve()를 너무 크게 잡으면 벡터가 불필요하게 늘어나 메모리를 많이 차지할 수 있다.

Solution 2. clear()로 벡터의 값을 지울 때, 벡터의 요소를 삭제할 수 있다.

 

Problem 3. clear()로 벡터의 요소는 없어지지만 capacity는 그대로 남아있다.

Solution 3. 이를 해결하기 위해 swap()을 사용하는데 이는 아래와 같다.

 

#include <vector>
using namespace std;

int main() {
    vector<int> vec = { 1,2,3,4,5 };
    vec.clear();
    cout << vec.capacity() << endl;  // 5 출력
    vector<int>().swap(vec);
    cout << vec.capacity() << endl;  // 0 출력
}

 

https://chan4im.tistory.com/19?category=1076581 

 

this.code(1).DS_ Array, array container & Vector (STL)

※ Array (배열) ※ 1차원 배열 배열은 주로 여러 개의 동일한 자료형의 데이터를 한꺼번에 만들 때 사용된다. 예를 들어 a0, a1, a2, a3, a4, a5라는 6개의 정수형 변수를 A[6]으로 간단하게 선언할 수 있

chan4im.tistory.com

 

 

vector에 값 입력받기  (cin >> vec[i]는 안된다??)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> v;

int main() {
    int num;
    for (int i = 0; i < 5; i++){
        //cin >> v[i];  // Err!
        cin >> num;
        v.push_back(num);
    }
    vector<int>::iterator it;
    sort(v.begin(), v.end(), greater<int>());

    for (it = v.begin(); it != v.end(); it++){
        cout << *it << ' ';
    }
}

 

 

 

 

 

 

 

 

 

 pair

★★★개인적으로 굉장히 유용하다고 생각되는 라이브러리★★★

feat. vector, sort

  • 두 자료형을 하나의 쌍(pair)으로 묶는다.
  • 첫번째 데이터는 first, 두번째 데이터는 second로 접근, make_pair(val1, val2)로 pair를 생성해준다.
  • vector, algorithm 의 헤더파일에 include 하고 있기에 별도의 헤더를 include할 필요가 없다.
#include <iostream>
using namespace std;

#include <vector>

int main(){
    pair<int, int> p1;
    cout << p1.first << ' ' << p1.second << endl; // 0 0 출력

    p1 = make_pair(1, 2);
    cout << p1.first << ' ' << p1.second << endl; // 1 2 출력

    pair<pair<int, int>, pair<int, int>> p2 = make_pair(make_pair(1, 2), make_pair(3, 4));

    cout << p2.first.first << ' ' << p2.first.second << endl;   // 1 2 출력
    cout << p2.second.first << ' ' << p2.second.second << endl; // 3 4 출력
}

 

pair로  vector, typedef, sort  다루기

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main(){
    pair<int, int> p1;
    cout << p1.first << ' ' << p1.second << endl; // 0 0 출력

    p1 = make_pair(1, 2);
    cout << p1.first << ' ' << p1.second << endl; // 1 2 출력

    pair<pair<int, int>, pair<int, int>> p2 = make_pair(make_pair(1, 2), make_pair(3, 4));

    cout << p2.first.first << ' ' << p2.first.second << endl;   // 1 2 출력
    cout << p2.second.first << ' ' << p2.second.second << endl; // 3 4 출력

    //vector와 pair
    vector<pair<int, int>> v;
    v.push_back(make_pair(10, 20));
    v.push_back(make_pair(30, 40));
    v.push_back(make_pair(50, 60));
    cout << v[0].first << ' ' << v[2].second << endl;

    // typedef를 이용한 방식
    typedef pair<int, int> P;
    vector<P> v1;
    v1.push_back(make_pair(300, 500));
    v1.push_back(make_pair(600, 400));
    v1.push_back(make_pair(100, 200));

    // first 따로, second 따로 정렬
    sort(v1.begin(), v1.end());
    vector<P>::iterator it;

    for (int i = 0; i < 3; i++)
        cout << v1[i].first << " " << v1[i].second << endl;
}


 

 

 

 

 

 

※ stack

#include <stack>

stack<데이터타입> 이름;

https://chan4im.tistory.com/22?category=1076581 

 

this.code(2).DS_ Stack & Stack Container(STL)

※ Stack 스택은 LIFO(Last-In-First-Out) 입출력 형태, 즉 후입선출 방식을 가진 자료구조이다. 위의 그림에서 4, 5번째 그림을 보자. Last In: 3 / First Out: 3 즉, 가장 마지막에 들어온 data가 가장 먼저 나..

chan4im.tistory.com

 

 

 

 

 stack, queue, deque priority queue, priority queue

 

※ queue 선언방식

#include <queue>

queue<데이터타입> 이름;

 

 

※ deque 선언방식

#include <deque>

deque<데이터타입> 이름;

https://chan4im.tistory.com/29?category=1076581 

 

★this.code(3).DS_ Queue & (STL): queue, deque

※ Queue 큐는 FIFO(First-In-First-Out) 입출력 형태, 즉 선입선출 방식을 가진 자료구조이다. enqueue와 dequeue의 시간복잡도는 둘 다 O(1)의 시간을 갖는다. 단, 탐색의 시간복잡도는 특정 data를 찾을 때까.

chan4im.tistory.com

 

 

 

 

※ priority queue 선언방식

#include <queue>

priority_queue<int> pq;
priority_queue<int, vector<int>, greater<int> > pq;
priority_queue<int, vector<int>, less<int> > pq;

가장 기본적인 것 부터 시작해 여러 방식으로 변형하며 사용할 수 있다.

우측 사진 출처:&nbsp;http://www.tcpschool.com/cpp/cpp_algorithm_functor

 

 

 

 

 

 

 

 

 

 

map

map은 각 node가 [key - value] 의 쌍(pair)으로 이루어진 트리이다. 

특히나 map의 가장 큰 특징은 중복을 허용하지 않는다는 것이다! => key가 중복되면 insert가 수행되지 않음

 

C++의 map 내부구현은 삽입, 삭제, 검색의 시간복잡도가 O(logn) 인 레드블랙트리로 구성되어 있다.

unordered_map은 해시 테이블이다.

 

※ map 선언방식 (삭제)

#include <map>

map<key_type, value_type> 이름;

※ map 삭제

※ map에서 찾고자 하는 데이터 확인 (search, find)

map에서 원하는 값을 찾고자 할 때, iterator를 사용한다.

만약 끝까지 원하는 값을 찾지 못하면, iterator는 map.end()를 반환한다.

 

find(k) 로 사용하며 key값 k에 해당하는 iterator를 반환한다.

map<string, int> mapset;

if (mapset.find("V2LLAIN") != mapset.end()){
    cout << "find!" << endl;
}
else
    cout << "not find!" << endl;

 

※ 반복문 데이터 접근 (first, second)

※ index 기반 iterator 활용 예제

map<string, int> mapset;

for (auto it = mapset.begin(); it != mapset.end(); it++) {
    cout << it->first << " " << it->second << endl;
}
cout << endl;

※ 범위기반 반복문 활용 예제

map<string, int> mapset;

for (auto it : mapset){
    cout << it.first << " " << it.second << endl;
}

 

※  map 사용 예제 (insert, search, iterator 구현)

#include <iostream>
#include <map>
using namespace std;

map<string, int> mapset;

int main() {

    mapset.insert({ "Alice", 100 });
    mapset.insert({ "Bob", 200 });

    if (mapset.find("Alice") != mapset.end())
    {
        cout << "find" << endl;
    }
    else {
        cout << "not find" << endl;
    }

    //인덱스기반
    for (auto iter = mapset.begin() ; iter !=  mapset.end(); iter++)
    {
        cout << iter->first << " " << iter->second << endl;
    }
    cout << endl;

    //범위기반
    for (auto iter : mapset) {
        cout << iter.first << " " << iter.second << endl;
    }
}

참고) https://life-with-coding.tistory.com/305?category=808106

 

 

 

 

 set

- set은 연관 컨테이너로 삽입, 삭제, 검색의 시간복잡도가 O(logn) 인 Binary Search Tree로 구현되어 있다.

- key라는 원소들의 "집합"으로 key값은 중복되지 않는다!

- insert()를 통한  자동적으로 오름차순 정렬이 가능하다.

중복을 피하면서 정렬까지 사용할 때 매우 유용하다!

 

insert(k) : 원소 k 삽입
begin() : 맨 첫번째 원소를 가리키는 iterator를 반환
end() : 맨 마지막 원소를 가리키는 iterator를 반환
find(k) : 원소 k를 가리키는 iterator를 반환
size() : set의 원소 수
empty() : 비어있는지 확인

 

 

 

 

 

algorithm

※ STL 알고리즘의 분류

find()는 2개의 입력 반복자로 지정된 범위에서 특정 값을 가지는 첫 번째 요소를 가리키는 입력 반복자를 반환 

for_each()는 2개의 입력 반복자로 지정된 범위의 모든 요소를 함수 객체에 대입한 후, 대입한 함수 객체를 반환 

 

copy()는 2개의 입력 반복자로 지정된 범위의 모든 요소를 출력 반복자가 가리키는 위치에 복사

swap()은 2개의 참조가 가리키는 위치의 값을 서로 교환

transform()은 2개의 입력 반복자로 지정된 범위의 모든 요소를 함수 객체에 대입후, 출력 반복자가 가리키는 위치에 복사

 

sort()는 2개의 임의 접근 반복자로 지정된 범위의 모든 요소를 비교, 오름차순정렬.

stable_sort()는 2개의 임의 접근 반복자로 지정된 범위의 모든 요소를 비교, 값이 같은 요소들의 상대적인 순서는 유지,  오름차순으로 정렬합니다.

binary_sort()는 정렬되어있는 경우(오름차순)에 한해서 탐색효율이 매우 좋고 적은 시간에 소요된다.

 

accumulate()는 두 개의 입력 반복자로 지정된 범위의 모든 요소의 합을 반환합니다.

 

 

※ 벡터의 오름차순과 내림차순 정렬 (feat. greater<int> 키워드)

§ sort() 함수 형식

단, custom_func()은 0 또는 1이 나오도록 해야해서 보통 bool형 함수를 많이 넣는다.

sort(v.begin(), v.end()); //형식이나
sort(v.begin(), v.end(), custom_func); //형식으로 사용가능하다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


int main() {
    vector<int> v;
    for (int i = 0; i < 5; i++) {
        int num; cin >> num;
        v.push_back(num);
    }
    sort(v.begin(), v.end());   // 오름차순
    sort(v.rbegin(), v.rend()); // 내림차순

    for (auto x: v) {
        cout << x;
    }
}

 

※ 벡터의 이진탐색 

 

http://www.tcpschool.com/cpp/cpp_algorithm_functor

 

 

 

 

 

 

 

iterator

STL에 저장된 요소를 반복적으로 순회해여 각각의 요소에 대한 접근을 제공하는 객체.

즉, 컨테이너의 구조,요소의 타입과 상관없이 컨테이너에 "저장된 요소"를 순회하는 과정을 일반화한 표현

 

[iterator를 쓰기 위한 요건]

1. 가리키는 요소의 값에 접근할 수 있어야 한다. => 참조 연산자(*)가 정의되어야 합니다.

2. 반복자 사이의 대입 연산, 비교 연산이 가능해야 합니다. => 대입, 관계 연산자가 정의되어야 합니다.

3. 가리키는 요소의 주변 요소로 이동할 수 있어야 합니다. => 증가 연산자(++)가 정의되어야 합니다.

int main() {
    vector<int> v(5);

    v.push_back(20);
    v.push_back(50);
    v.push_back(10);

    for (int i = 0; i < 5; i++)
        cin >> v[i];

    vector<int>::iterator it;
    for (it = v.begin(); it != v.end(); it++) {
        cout << *it << ' ';
    }
    
    //1 2 3 4 5 20 50 10 출력
}

 

 

 

표준 컨테이너 시간 복잡도 (The C++ Programming Language)

 

 

 

 

 

※ bitset

비트연산의 간편화를 위해 사용하는 라이브러리

#include <bitset>

int main() {
    bitset<100000> a(76),b(44); // 각각 76, 44의 비트가 입력됨
    cout << (a & b) << '\n';
    cout << (a | b) << '\n';
    cout << (a ^ b) << '\n';
    cout << (~a) << '\n';
    cout << (~b) << '\n';
    return 0;
}

+ Recent posts