{{ label!='' ? 'Label : ' : (q!='' ? '검색 : ' : '전체 게시글') }} {{ label }} {{ q }} {{ ('('+(pubs|date:'yyyy-MM')+')') }}

[C++] 스터디 CPPALOM 10주차: 뇌를 자극하는 C++ STL Chap 8

파워 포인트 파일(.pptx)을 Markdown으로 변환하여 업로드하였음)

 
# <br>CPPALOM

# <br>10주차 – 뇌를 자극하는 C++ STL Chap 8
한수빈

# <br>STL 알고리즘

* STL에는 100여 개의 알고리즘이 있으며, 크게 다음 일곱 가지로 분류할 수 있다:
  * 원소를 수정하지 않는 알고리즘(nonmodifying algorithms)
  * 원소를 수정하는 알고리즘(modifying algorithms)
  * 제거 알고리즘(removing algorithms)
  * 변경 알고리즘(mutating algorithms)
  * 정렬 알고리즘(sorting algorithms)
  * 정렬된 범위 알고리즘(sorted range algorithms)
  * 수치 알고리즘(numeric algorithms)
* 대부분의 알고리즘은 헤더 <algorithm>에 정의되며, 수치관련 알고리즘은 <numeric>에 정의된다.

# <br>원소를 수정하지 않는 알고리즘

| 알고리즘 | 설명 |
| :-: | :-: |
| f=for_each(b,e,f) | 구간 [b,e)의 모든 원소에 f(*p)동작을 적용한다. f를 다시 되돌려준다. |
| n=count_if(b,e,f) | n은 구간 [b,e)의 원소 중 f(*p)가 참인 원소의 개수 |
| equal(b,e,b2,f) | [b,e)와 [b2,b2+(e-b))의 모든 원소가 f(*p,*q)가 참인가? |
| p=find(b,e,x) | p는 구간[b,e)에서 x와 같은 첫 원소의 반복자 |
| f=for_each(b,e,f) | 구간[b,e)의 모든 원소에 f(*p) 동작을 적용한다. f를 다시 되돌려준다. |
| … |  |

# <br>count_if()

count()의 조건자 버전이다.

조건에 맞는 원소의 개수를 구할 수 있다.

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool Pred(int n)
{
    return 25 < n ;
}
void main( )
{  
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    // 구간 [v.begin(), v.end())에서 25 보다 큰 원소의 개수를 반환
    int n = count_if(v.begin(), v.end(), Pred);
    cout <<"25보다 큰 원소의 개수 :"<< n << endl;
}
```

```C++
10 20 30 40 30 50
30의 개수: 2
```

# <br>find()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool Pred(int n)
{
    return 35 < n ;
}
void main( )
{  
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    vector<int>::iterator iter;
    iter = find(v.begin(), v.end(), 20);
    if( iter != v.end() )
        cout <<*iter <<"을 찾다!" << endl;
    iter = find_if(v.begin(), v.end(), Pred);
    if( iter != v.end() )
        cout <<"순차열에서 35보다 큰 첫 번째 원소: "<< *iter << endl;
}
```

* p=find(b,e,x)
  * p는 구간[b,e)에서 x와 같은 첫 원소의 반복자
* 다음은 find()와 find_if()를 이용해 원소를 찾는 예제이다.

```C++
10 20 30 40 50
20을 찾다!
순차열에서 35보다 큰 첫 번째 원소: 40
```

# <br>for_each()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void Print(int n)
{
    cout << n << " ";
}
void main( )
{  
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    for_each(v.begin(), v.begin()+2, Print);
    cout << endl;
    for_each(v.begin(), v.begin()+4, Print);
    cout << endl;
    //[v.begin(), v.end()) 구간의 원소 출력
    for_each(v.begin(), v.end(), Print);
    cout << endl;
}
```

* f=for_each(b,e,f)
  * 구간[b,e)의 모든 원소에 f(*p) 동작을 적용한다. f를 다시 되돌려준다.
* 다음은 for_each() 알고리즘을 사용하여 모든 원소를 출력하는 예제이다.

```C++
10 20
10 20 30 40
10 20 30 40 50
```

# <br>mismatch()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50);
    vector<int> v2;
    v2.push_back(10);
    v2.push_back(20);
    v2.push_back(30);
    v2.push_back(80);
    v2.push_back(90);
    pair<vector<int>::iterator, vector<int>::iterator> iter_pair;
    iter_pair = mismatch(v1.begin(),v1.end(),v2.begin());
    cout <<"v1: "<< *iter_pair.first <<", " <<"v2: "<<*iter_pair.second << endl;
}
```

mimstach(b,e,b2)는 구간 [b,e)와 구간[b2,b2+(e-b))의 모든 원소를 하나씩 비교하여 원소 값이 서로 다른 첫 원소의 반복자 쌍을 반환한다.

# <br>search()

```C++
void main( )
{
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50);
    v1.push_back(60);
    v1.push_back(70);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50);
    vector<int> v2;
    v2.push_back(30);
    v2.push_back(40);
    v2.push_back(50);
    vector<int>::iterator iter;
    iter = search(v1.begin(), v1.end(), v2.begin(), v2.end());
    if( iter != v1.end() )
    {
        // 일치하는 첫 번째 순차열의 첫 원소의 반복자 iter
        cout << "iter : " << *iter << endl;
        cout << "iter-1 : " <<*(iter-1) << endl;
        cout << "iter+1 : " <<*(iter+1) << endl;;   
    }
}
```

search(b1, e1, b2, e2)는 구간 [b1,e1] 사이에서 [b2,e2)와 일치하는 첫 번째 순차열의 첫 원소의 반복자를 반환한다.

```C++
iter : 30
iter-1 : 20
iter+1 : 40
```

# <br>원소를 수정하는 알고리즘

| 알고리즘 | 설명 |
| :-: | :-: |
| p=copy(b,e,t) | 구간 [b,e)의 모든 원소를 [t,t+(e-b))로 모두 복사한다. |
| fill(b,e,x) | 구간 [b,e)의 원소를 x로 채운다. |
| generate(b,e,f) | 구간 [b,e)의 모든 원소를 f()로 채운다. |
| p=merge(b,e,b2,e2,t) | 정렬된 순차열 [b,e)와 [b2,e2)를 [t,p)로 합병 정렬한다. |
| replace(b,e,x,x2) | 구간 [b,e)의 x인 원소를 x2로 수정한다. |
| transform(b,e,b2,t,f) | 구간 [b,e)와 [b2, b2+(e-b))의 두 순차열의 반복자 p, q일 때 모든 원소를 f(*p,*q)하여 [t, t+(e-b))에 저장한다. p는 저장된 마지막 원소의 반복자이다. |
| … |  |

# <br>copy()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50);
    vector<int> v2(5); //size 5인 vector 생성
    vector<int>::iterator iter;
    // 구간 [v1.begin(), v1.end())의 모든 원소를 [v2.begin(), iter)의 순차열로 복사.
    iter = copy(v1.begin(), v1.end(), v2.begin());
    cout <<"v2 마지막 원소: " << *(iter-1) << endl;
    cout << "v1 : ";
    for(vector<int>::size_type i = 0; i < v1.size(); ++i)
        cout << v1[i] <<" ";
    cout << endl;
    cout << "v2 : ";
    for(vector<int>::size_type i = 0; i < v2.size(); ++i)
        cout << v2[i] <<" ";
    cout << endl;
}
```

* 순차열에서 다른 순차열로 원소를 복사할 수 있다.
* 목적지 순차열로 복사 동작을 수행할 때 두 가지 모드의 복사 동작이 있다.
  * 하나는 덮어쓰기(overwrite)이며,
  * 하나는 삽입(insert)이다.
  * 모든 알고리즘의 기본 동작은 덮어쓰기이며 반복자 어댑터 등을 사용하여 삽입을 할 수 있다.

```C++
v2 마지막 원소: 50
v1: 10 20 30 40 50
v2: 10 20 30 40 50
```

# <br>fill()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    // 구간 [v.begin(), v.end())의 모든 원소를 0으로 채운다.
    fill(v.begin(), v.end(), 0);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    // 구간 [v.begin(), v.begin()+3)의 모든 원소를 55로 채운다.
    fill_n(v.begin(), 3, 55);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
}
```

순차열을 특정 값으로 채울 수 있다.

다음은 v1의 순차열을 모두 0으로 채우거나 일부를 55로 채우는 fill(), fill_n() 알고리즘 예제이다.

```C++
v : 0 0 0 0 0
v : 55 55 55 0 0
```

# <br>generate()

```C++
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    // [v.begin(), v.end())의 원소를 1~5로 채운다.
    generate(v.begin(), v.end(), Integer(1) );
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    // [v.begin(), v.end())의 원소를 100~104로 채운다.
    generate(v.begin(), v.end(), Integer(100) );
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    // [v.begin(), v.begin()+3)의 원소를 1~3로 채운다.
    generate_n(v.begin(), 3, Integer(1) );
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
}
```

순차열의 모든 원소를 단순한 동작의 값으로 수정할 수 있다.

다음은 초기값부터 정수를 1씩 증가하며 순차열을 채우는 generate(), generate_n() 예제이다.

```C++
class Integer
{
    int data;
public:
    explicit Integer(int d = 0):data(d) { }
    int operator()( )
    {
        return data++;
    }
};
```

```C++
v : 10 20 30 40 50
v : 1 2 3 4 5
v : 100 101 102 103 104
v : 1 2 3 103 104
```

# <br>merge()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(30);
    v1.push_back(50);
    v1.push_back(60);
    v1.push_back(80);
    vector<int> v2;
    v2.push_back(20);
    v2.push_back(40);
    v2.push_back(70);
    vector<int> v3(10); //size 10인 vector 생성 
    vector<int>::iterator iter_end;
    iter_end = merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
    cout << "v1 : ";
    for(vector<int>::size_type i = 0; i < v1.size(); ++i)
        cout << v1[i] <<" ";
    cout << endl;
    cout << "v2 : ";
    for(vector<int>::size_type i = 0; i < v2.size(); ++i)
        cout << v2[i] <<" ";
    cout << endl;
    cout << "v3 : ";
    for(vector<int>::size_type i = 0; i < v3.size(); ++i)
        cout << v3[i] <<" ";
    cout << endl;
    cout << "v3(합병 순차열): " << *v3.begin() <<'~'<< *(iter_end-1) <<endl;
}
```

정렬된 두 순차열을 하나의 정렬된 순차열로 합병할 수 있다.

다음은 v1의 순차열과 v2의 순차열을 v3의 순차열로 합병 정렬하는 merge() 예제이다.

```C++
v1 : 10 30 50 60 80
v2 : 20 40 70
v3 : 10 20 30 40 50 60 70 80 0 0
v3(합병 순차열): 10~80
```

# <br>replace()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(30);
    v.push_back(30);
    v.push_back(50);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    replace(v.begin(), v.end(), 30, 0);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
}
```

순차열의 특정 원소를 다른 값으로 수정할 수 있다.

다음은 순차열의 원소 30을 모두 0으로 수정하는 replace() 예제이다.

```C++
v : 10 20 30 40 30 30 50
v : 10 20 0 40 0 0 50
```

# <br>transform()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int Func(int n)
{
    return n+5;
}
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    transform(v.begin(), v.end(), v.begin(), Func);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
}
```

* 순차열의 모든 원소에 사용자의 정책을 반영할 수 있다.
  * 원본의 순차열의 변화 없이 목적지의 순차열로 저장한다.
* 다음은 v 순차열의 모든 원소를 5씩 증가시키는 transform() 예제이다.

```C++
v : 10 20 30 40 50
v : 15 25 35 45 55
```

# <br>제거 알고리즘

| 알고리즘 | 설명 |
| :-: | :-: |
| p=remove(b,e,x) | 구간 [b,e)의 순차열을 x 원소가 남지 않도록 덮어쓰기로 이동한다. 알고리즘 수행 후 순차열은 [b,p)가 된다. |
| p=remove_copy(b,e,t,x) | 구간 [b,e]의 순차열에서 *p==x가 아닌 원소만 순차열 [t,p)에 복사한다. |
| unique(b,e) | 구간 [b,e)의 순차열을 인접한 중복 원소가 남지 않게 덮어쓰기로 이동한다. 알고리즘 수행 후 순차열은 [b,p)가 된다. |
| p=uniqute_copy(b,e,t) | 구간 [b,e)의 순차열에서 인접한 중복 원소가 아닌 원소를 순차열 [t,p)에 복사한다. |
| … |  |

# <br>remove()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    vector<int>::iterator iter_end;
    iter_end = remove(v.begin(), v.end(), 30);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    cout << "remove 후 [v.begin(), iter_end) 순차열: ";
    for(vector<int>::iterator iter=v.begin(); iter != iter_end; ++iter)
        cout << *iter <<" ";
    cout << endl;
}
```

* 순차열에서 특정 원소를 남지 않게 한다.
  * 이 때 remov는 실제 원소를 제거하지 않는다.
  * 다음 원소를 앞으로 이동한다.
  * size에는 변동이 없으며 remove() 이후의 순차열은 [b,p)가 된다.

```C++
v : 10 20 30 40 50
v : 10 20 40 50 50
remove 후 [v.begin(), iter_end) 순차열: 10 20 40 50
```

# <br>unique()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(30);
    v.push_back(40);
    v.push_back(40);
    v.push_back(30);
    v.push_back(50);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    vector<int>::iterator iter_end;
    iter_end = unique(v.begin(), v.end());
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    cout << "[v.begin(), iter_end) : ";
    for(vector<int>::iterator iter = v.begin(); iter != iter_end; ++iter)
        cout << *iter <<" ";
    cout << endl;
}
```

* 순차열의 인접 원소를 유일하게 만들 수 있다.
  * 알고리즘 수행 후 순차열은 [b,p)가 된다.
  * remove()와 마찬가지로 원소를 논리적으로만 제거한다.
* 다음은 v1 순차열에서 인접한 중복 원소 30과 40 원소를 유일하게 만드는 unique() 예제이다.

```C++
v : 10 20 30 30 40 40 30 50
v : 10 20 30 40 30 50 30 50
[v.begin(), iter_end) : 10 20 30 40 30 50
```

# <br>변경 알고리즘

| 알고리즘 | 설명 |
| :-: | :-: |
| bool=next_permuntation(b,e) | 구간 [b,e)의 순차열을 사전순 다음 순열이 되게 한다. 더 이상 다음 순열이 없는 마지막 순열이라면 bool은 false이다. |
| bool=prev_permutation(b,e) | 구간 [b,e)의 순차열을 사전순 이전 순열이 되게 한다. 더 이상 이전 순열이 없는 첫 순열이라면 bool은 false이다. |
| p=partition(b,e,f) | 구간 [b,e)의 순차열 중 f(*p)가 참인 원소는 [b,p)의 순차열에 거짓인 원소를 [p,e)의 순차열로 분류한다. |
| random_shuffle(b,e) | 구간 [b,e)의 순차열을 랜덤으로 뒤섞는다. |
| reverse(b,e) | 구간[b,e)의 순차열을 뒤집는다. |
| rotate(b,m,e) | 구간 [b,e)의 순차열을 왼쪽으로 회전시킨다. 첫 원소와 마지막 원소가 연결된 것처럼 모든 원소가 왼쪽으로 (m-b)만큼씩 이동한다. |
| … |  |

# <br>next_permutation()

* 원소의 순서를 순열처럼 변경할 때 next_permutation()과 prev_permutation()을 사용한다.
  * 해당 순차열을 사전순 순열로 다음 순열로 변경한다.

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    cout << next_permutation(v.begin(), v.end()) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    cout << next_permutation(v.begin(), v.end()) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    cout << next_permutation(v.begin(), v.end()) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    cout << next_permutation(v.begin(), v.end()) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    cout << next_permutation(v.begin(), v.end()) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    // 마지막 순열이므로 next_permutation()은 false 반환
    cout << next_permutation(v.begin(), v.end()) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
}
```

```C++
v : 10 20 30
1
v : 10 30 20
1
v : 20 10 30
1
v : 20 30 10
1
v : 30 10 20
1
v : 30 20 10
0
v : 10 20 30
```

# <br>조건자 버전 next_permutation()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool Pred(const Point& left, const Point& right)
{   //순열의 비교 기준으로 사용될 이항 조건자
    return left.GetY() < right.GetY();
}
void main( )
{
    vector<Point> v;
    v.push_back(Point(5, 1));
    v.push_back(Point(7, 2));
    v.push_back(Point(5, 3));
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    cout << next_permutation(v.begin(), v.end(), Pred) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    cout << next_permutation(v.begin(), v.end(), Pred) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    cout << next_permutation(v.begin(), v.end(), Pred) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    cout << next_permutation(v.begin(), v.end(), Pred) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    cout << next_permutation(v.begin(), v.end(), Pred) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
    // Point의 y를 기준으로 마지막 순열이므로 next_permutation()은 false 반환
    cout << next_permutation(v.begin(), v.end(), Pred) << endl;;
    cout << "v : " << v[0] <<" " << v[1] <<" " << v[2] << endl;
}
```

조건자 버전으로 역시 사용할 수 있다.

```C++
class Point
{
    int x, y;
public: 
    explicit Point(int _x=0, int _y=0):x(_x), y(_y) { }
    int GetX( ) const { return x; }
    int GetY( ) const { return y; }
};
ostream& operator<<(ostream& out, const Point& arg)
{   //Point 객체 cout 출력을 위한 연산자 오버로딩
    out <<"(" <<arg.GetX() <<"," <<arg.GetY() <<")";
    return out;
}
```

```C++
v : (5,1) (7,2) (5,3)
1
v : (5,1) (5,3) (7,2)
1
v : (7,2) (5,1) (5,3)
1
v : (7,2) (5,3) (5,1)
1
v : (5,3) (5,1) (7,2)
1
v : (5,3) (7,2) (5,1)
0
v : (5,1) (7,2) (5,3)
```

# <br>partition()

```C++
bool Pred(int n)
{
    return n < 40;
}
void main( )
{
    vector<int> v;
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    v.push_back(10);
    v.push_back(20);
    v.push_back(60);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    vector<int>::iterator iter_sep;
    // 40 원소를 기준으로 미만과 이상을 분류한다.
    iter_sep = partition(v.begin(), v.end(), Pred);
    cout <<"40미만의 순차열: ";
    for(vector<int>::iterator iter=v.begin(); iter != iter_sep; ++iter)
        cout << *iter <<" ";
    cout << endl;
    cout <<"40이상의 순차열: ";
    for(vector<int>::iterator iter=iter_sep; iter != v.end(); ++iter)
        cout << *iter <<" ";
    cout << endl;
}
```

순차열의 원소를 특정 조건에 따라 분류할 수 있다.

다음은 40 원소를 기준으로 40 미만과 40 이상의 원소를 분류하는 partition() 예제이다.

```C++
v : 30 40 50 10 20 60
40미만의 순차열: 30 20 10
40이상의 순차열: 50 40 60
```

# <br>random_shuffle()

```C++
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    //#include <ctime>, #include <cstdlib> 추가 랜덤 초기값
    //srand( (unsigned)time(NULL) ); 
    // 원소를 뒤섞는다.
    random_shuffle(v.begin(), v.end());    
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    // 원소를 뒤섞는다.
    random_shuffle(v.begin(), v.end());    
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
}
```

* 순차열 원소의 순서를 무작위로 뒤섞을 수 있다.
  * 실행 결과가 같게 나오는 것은 기본 랜덤기의 시드 값이 1이기 때문이다.
  * 출력 결과를 바꾸고 싶다면 srand()를 이용한다.

```C++
v : 10 20 30 40 50
v : 50 20 40 30 10
v : 50 40 30 10 20
```

# <br>정렬 알고리즘

| 알고리즘 | 설명 |
| :-: | :-: |
| make_heap(b,e) | 힙을 생성한다. 구간[b,e)의 순차열을 힙 구조로 변경한다. |
| push_heap(b,e) | 힙에 원소를 추가한다. 보통 push_back() 멤버 함수와 같이 사용되며, 구간 [b,e)의 순차열을 다시 힙 구조가 되게 한다. |
| pop_heap(b,e) | 힙에서 원소를 제거한다. 구간 [b,e)의 순차열의 가장 큰 원소(첫 원소)를 제거한다. |
| sort_heap(b,e) | 구간 [b,e)의 순차열을 힙 구조를 이용해 정렬한다. |
| nth_element(b,m,e) | 구간 [b,e)의 순차열에서 m번째 자리를 기준으로 partition한다. (Quick Selection) |
| sort(b,e) | 퀵 정렬을 기반으로 정렬한다. 구간 [b,e)를 정렬한다. |
| stable_sort(b,e) | 머지 정렬을 기반으로 정렬한다. 구간 [b,e)를 정렬한다. |
| partial_sort(b,m,e) | 힙 정렬을 기반으로 정렬한다. 구간 [b,e)의 원소 중 m-b개 만큼의 상위 원소를 정렬하여 [b,m) 순차열에 놓는다. |
| … |  |

# <br>make_heap()

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    v.push_back(60);
    cout << "v : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    make_heap(v.begin(), v.end());
    cout << "v[힙 생성] : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
}
```

주어진 순차열을 힙 구조로 만들 수 있다.

```C++
v : 10 20 30 40 50 60
v[힙 생성] : 60 50 30 40 20 10
```

# <br>nth_element()

* 순차열의 원소를 m번째 자리를 기준으로 partition한다.
  * 참고: Quick Selection 알고리즘

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v;
    for(int i = 0 ; i < 100 ; ++i)
        v.push_back( rand()%1000 );
    nth_element(v.begin(), v.begin()+20, v.end());
    cout << "v[상위 20개] : ";
    for(vector<int>::size_type i = 0; i < 20; ++i)
        cout << v[i] <<" ";
    cout << endl;     
    cout << "v[하위 80개] : ";
    for(vector<int>::size_type i = 20; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;     
}
```

```C++
v[상위 20개] : 41 106 141 35 169 253 37 153 82 35 118 145 190 84 101 6 264 40 281 288
v[하위 80개] : 292 299 308 316 322 323 333 334 350 358 370 376 382 391 393 421 436 439 446 447 464 467 478 491 500 529 537 538 538 541 724 962 705 827 995 942 827 604 902 961 741 711 547 842 723 664 673 942 859 912 868 805 890 729 757 662 644 811 667 648 629 623 703 954 756 840 966 869 931 778 944 771 626 726 895 718 894 716 929 548
```

# <br>stable_sort()

```C++
bool Greater(int left, int right)
{
    return left > right;
}
void main( )
{
    vector<int> v;
    v.push_back(30);
    v.push_back(50);
    v.push_back(30);
    v.push_back(20);
    v.push_back(40);
    v.push_back(10);
    v.push_back(40);
    cout << "v[정렬 전] : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;     
    stable_sort(v.begin(), v.end());
    cout << "v[정렬 less] : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;     
    stable_sort(v.begin(), v.end(), Greater );
    //sort(v.begin(), v.end(), greater<int>() );
    cout << "v[정렬 greater] : ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;     
}
```

sort(): 퀵 정렬 사용

stable_sort(): 머지 정렬 사용

partial_sort(): 힙 정렬 사용

```C++
v[정렬 전] : 30 50 30 20 40 10 40
v[정렬 less] : 10 20 30 30 40 40 50
v[정렬 greater] : 50 40 40 30 30 20 10
```

# <br>정렬된 범위 알고리즘

| 알고리즘 | 설명 |
| :-: | :-: |
| binary_search(b,e,x) | 구간 [b,e)의 순차열에 x와 같은 원소가 있는가? |
| includes(b,e,b2,e2) | 구간 [b2,e2)의 모든 원소가 구간 [b,e)에도 있는가? |
| p=lower_bound(b,e,x) | p는 구간 [b,e)의 순차열에서 x 이상의 첫 원소의 반복자이다. |
| p=upper_bound(b,e,x) | p는 구간 [b,e)의 순차열에서 x 미만의 첫 원소의 반복자이다. |
| pair(p1,p2)=equal_range(b,e,x) | 구간 [p1,p2)의 순차열은 구간 [b,e)의 순차열에서 x와 같은 원소의 구간(순차열)이다. [lower_bound(), upper_bound())의 순차열과 같다. |
| … |  |

# <br>binary_search()

* 이진 검색 알고리즘이다.
  * 해당 원소가 존재하면 true, 없으면 false를 반환한다.
  * 기본 정렬 기준인 less로 정렬돼 있다는 전제 하에 동작한다.
  * a==b 연산은 사용되지 않으며, !(a<b) && !(b<a) 연산을 사용한다.

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    if( binary_search(v.begin(), v.end(), 20) )
        cout << "20 원소가 존재합니다." << endl;
    else
        cout << "20 원소가 존재하지 않습니다." << endl;
}
```

# <br>조건자 버전 binary_search()

```C++
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    v.push_back(20);
    cout << "[v 원본]: ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    sort(v.begin(), v.end());        
    cout << "[v: less 정렬]: ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    cout <<"비교 less 찾기: "<< binary_search(v.begin(), v.end(), 20, less<int>()) << endl;
    sort(v.begin(), v.end(), greater<int>());        
    cout << "[v: greater 정렬]: ";
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    cout <<"비교 greater 찾기: "<< binary_search(v.begin(), v.end(), 20, greater<int>()) << endl;
}
```

* 조건자를 이용해서 이진 탐색을 할 수 있다.
  * 해당 순차열은 해당 조건자를 이용해 정렬되어 있어야 한다.

```C++
[v 원본]: 10 30 40 50 20
[v: less 정렬]: 10 20 30 40 50
비교 less 찾기: 1
[v: greater 정렬]: 50 40 30 20 10
비교 greater 찾기: 1
```

# <br>includes()

```C++
void main( )
{
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50);
    vector<int> v2;
    v2.push_back(10);
    v2.push_back(20);
    v2.push_back(40);
    vector<int> v3;
    v3.push_back(10);
    v3.push_back(20);
    v3.push_back(60);
    if( includes(v1.begin(), v1.end(), v2.begin(), v2.end()) )
        cout <<"v2는 v1의 부분 집합" << endl;
    else 
        cout <<"v2는 v1의 부분 집합 아님" << endl;
    if( includes(v1.begin(), v1.end(), v3.begin(), v3.end()) )
        cout <<"v3는 v1의 부분 집합" << endl;
    else 
        cout <<"v3는 v1의 부분 집합 아님" << endl;
    //정렬 기준을 greater<int> 설정
    sort(v1.begin(), v1.end(), greater<int>());
    sort(v2.begin(), v2.end(), greater<int>());
    //비교 기준을 greater<int> 설정
    if( includes(v1.begin(), v1.end(), v2.begin(), v2.end(), greater<int>()) )
        cout <<"greater정렬 순차열: v2는 v1의 부분 집합" << endl;
}
```

한 순차열이 다른 순차열의 부분 집합인지 판단할 수 있다.

다음은 v2와 v3의 원소가 v1에 포함되는지 판단하는 includes() 예제이다.

```C++
v2는 v1의 부분 집합
v3는 v1의 부분 집합 아님
greater정렬 순차열: v2는 v1의 부분 집합
```

# <br>lower_bound(), upper_bound()

연관 컨테이너의 lower_bound(), upper_buond()와 유사한 알고리즘이다.

다음은 v 순차열에서 30 원소의 순차열을 찾는 lower_bound(), upper_bound() 예제이다.

```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(30);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    vector<int>::iterator iter_lower, iter_upper;
    iter_lower = lower_bound(v.begin(), v.end(), 30);
    iter_upper = upper_bound(v.begin(), v.end(), 30);
    cout<<"30 원소의 순차열 [iter_lower, iter_upper): ";
    for(vector<int>::iterator iter=iter_lower; iter != iter_upper; ++iter)
        cout << *iter << " ";
    cout << endl;
}
```

```C++
30 원소의 순차열 [iter_lower, iter_upper): 30 30 30
```

# <br>수치 알고리즘

| 알고리즘 | 설명 |
| :-: | :-: |
| x2=accumulate(b,e,x) | x2는 x를 초기값으로 시작한 구간 [b,e) 순차열 원소의 합이다. |
| x2=inner_product(b,e,b2,x) | x2는 x를 초기값으로 시작한 구간 [b,e)와 구간 [b2,b2+e-b)의 내적이다. |
| adjacent_difference(b,e,t) | 구간[b,e)의 인접 원소와의 차를 순차열 [t,p)에 저장한다. |
| p=partial_sum(b,e,t) | 구간 [b,e)의 현재 원소까지의 합을 순차열 [t,p)에 저장한다. |
| … |  |

# <br>accumulate()

* 순차열의 모든 원소를 누적하려면 for_each()나 transform()을 사용할 수 있다.
  * accumulate()를 이용해 좀 더 간단하게 처리할 수 있다.
* 다음은 v 원소의 합을 출력하는 accumulate() 예제이다.

```C++
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
void main( )
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    cout << "v: ";    
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] <<" ";
    cout << endl;
    cout << accumulate(v.begin(), v.end(), 0) << endl;
    cout << accumulate(v.begin(), v.end(), 100) << endl;
}
```

```C++
v: 10 20 30 40 50
150
250
```

# <br>inner_product()

* 두 순차열의 내적을 구할 수 있다.
  * inner_product(b,e,b2,x)에서 x는 초기값이 된다. 즉, 결과에 더해진다.

```C++
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
void main( )
{
    vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);
    v1.push_back(4);
    v1.push_back(5);
    vector<int> v2;
    v2.push_back(2);
    v2.push_back(2);
    v2.push_back(2);
    v2.push_back(2);
    v2.push_back(2);
    // 0 + 1*2 + 2*2 + 3*2 + 4*2 + 5*2
    cout << inner_product(v1.begin(), v1.end(), v2.begin(), 0) << endl;
    // 100 + 1*2 + 2*2 + 3*2 + 4*2 + 5*2
    cout << inner_product(v1.begin(), v1.end(), v2.begin(), 100) << endl;
}
```

# <br>adjacent_difference()

* 순차열에서 원소 간의 차를 구할 수 있다.
  * p=adjacent_difference(b,e,t))에서 각 구간의 차이를 [t,p)에 저장한다.

```C++
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
void main( )
{
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50);
    cout << "v1: ";    
    for(vector<int>::size_type i = 0; i < v1.size(); ++i)
        cout << v1[i] <<" ";
    cout << endl;
    vector<int> v2(5); //size: 5인 vector 생성
    vector<int>::iterator iter_end;
    iter_end = adjacent_difference(v1.begin(), v1.end(), v2.begin());
    cout << "v2: ";    
    for(vector<int>::size_type i = 0; i < v2.size(); ++i)
        cout << v2[i] <<" ";
    cout << endl;
}
```

```C++
v1: 10 20 30 40 50
v2: 10 10 10 10 10
```

# <br>partial_sum()

* 순차열에서 현재 원소까지의 합을 구할 수 있다.
  * p=partial_sum(b,e,t)는 구간 [b,e)의 현재 원소까지의 누적합을 순차열 [t,p)에 저장한다.

```C++
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
void main( )
{
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50);
    cout << "v1: ";    
    for(vector<int>::size_type i = 0; i < v1.size(); ++i)
        cout << v1[i] <<" ";
    cout << endl;
    vector<int> v2(5); //size: 5인 vector 생성
    vector<int>::iterator iter_end;
    iter_end = partial_sum(v1.begin(), v1.end(), v2.begin());
    cout << "v2: ";    
    for(vector<int>::size_type i = 0; i < v2.size(); ++i)
        cout << v2[i] <<" ";
    cout << endl;
}
```

```C++
v1: 10 20 30 40 50
v2: 10 30 60 100 150
```

댓글

이 블로그의 인기 게시물

[코딩의탑] 4층: 툰 쉐이딩

[코딩의탑] 3층: 바다 렌더링

[코딩의탑] 5층: 포탈(Portal), 더 나아가기