기존 문제점
- 예제를 하나씩 풀어봤는데, 가독성이 좋지 않다는 걸 알 수 있다. 코드는 굉장히 단순하지만, 그래도 분석하는데 최소 10초는 걸릴 수 있다고 생각할 수 있다. 또한 정형화된 패턴이 아니다보니 프로그래머 마다 스타일이 다를 수도 있다. 그래서 바로 보자마자 이해하기 어렵다.
- 더욱 큰 단점은 코드는 vector를 사용했기 때문에, 코드 내에선 특정 인덱스에 접근(v[i])하는 임의 접근 코드가 들어가있지만, 만약 삽입/삭제의 효율 때문에 list로 바꿔야 한다면 문법의 문제가 생길것이다.
#include <list>
#include <map>
#include <iostream>
using namespace std;
int main()
{
srand(static_cast<unsigned int>(time(nullptr)));
vector<int> v;
for (int i = 0; i < 100; ++i)
{
int num = rand() % 100;
v.push_back(num);
}
// Q1) number 라는 숫자가 벡터에 체크하는 기능 (bool, 첫 등장 iterator)
{
int number = 50;
bool found = false;
vector<int>::iterator it = v.end();
for (unsigned int i = 0; i < v.size(); ++i)
{
if (v[i] == number)
{
found = true;
it = v.begin() + i;
break;
}
}
}
// Q2) 11로 나뉘는 숫자가 벡터에 있는지 체크하는 기능 (bool, 첫 등장 iterator)
{
bool found = false;
vector<int>::iterator it;
for (unsigned int i = 0; i < v.size(); ++i)
{
int data = v[i];
if ((data % 11) == 0)
{
found = false;
it = v.begin() + i;
break;
}
}
}
// Q3) 홀수인 숫자의 개수는? (count)
{
int count = 0;
for (unsigned int i = 0; i < v.size(); ++i)
{
int data = v[i];
if (data % 2) != 0)
count++;
}
}
// Q4) 벡터에 들어가있는 모든 숫자들에 3을 곱해주세요.
{
for (unsigned int i = 0; i < v.size(); ++i)
{
v[i] *= 3;
}
}
// Q5) 홀수인 데이터를 일괄 삭제
{
for (auto it = v.begin(); it != v.end(); )
{
if ((*it % 2) != 0)
it = v.erase(it);
else
++it;
}
}
}
알고리즘 사용
#include <list>
#include <map>
#include <iostream>
// 주제 : 알고리즘
#include <algorithm>
using namespace std;
int main()
{
// 자료구조 (데이터를 저장하는 구조)
// 알고리즘 (데이터를 어떻게 사용할 것인가?)
// find
// find_if
// count
// count_if
// all_of
// any_of
// for_each
// remove
// remove_if
srand(static_cast<unsigned int>(time(nullptr)));
vector<int> v;
for (int i = 0; i < 100; ++i)
{
int num = rand() % 100;
v.push_back(num);
}
// Q1) number 라는 숫자가 벡터에 체크하는 기능 (bool, 첫 등장 iterator)
{
int number = 50;
bool found = false;
vector<int>::iterator it = v.end();
for (unsigned int i = 0; i < v.size(); ++i)
{
if (v[i] == number)
{
found = true;
it = v.begin() + i;
break;
}
}
auto itFind = find(v.begin(), v.end(), number);
if (itFind == v.end())
cout << "못 찾았음" << endl;
else
cout << "찾았음" << endl;
}
// Q2) 11로 나뉘는 숫자가 벡터에 있는지 체크하는 기능 (bool, 첫 등장 iterator)
{
bool found = false;
vector<int>::iterator it;
for (unsigned int i = 0; i < v.size(); ++i)
{
int data = v[i];
if ((data % 11) == 0)
{
found = false;
it = v.begin() + i;
break;
}
}
struct CanDivideBy11
{
bool operator()(int& n)
{
return (n % 11) == 0;
}
};
vector<int>::iterator itFind = std::find_if(v.begin(), v.end(), CanDivideBy11());
vector<int>::iterator itFind = std::find_if(v.begin(), v.end(), [](int n) { return (n % 11) == 0; });
if (itFind == v.end())
cout << "못 찾았음" << endl;
else
cout << "찾았음" << endl;
}
// Q3) 홀수인 숫자의 개수는? (count)
{
int count = 0;
for (unsigned int i = 0; i < v.size(); ++i)
{
int data = v[i];
if (data % 2) != 0)
count++;
}
struct IsOdd
{
bool operator()(int& n)
{
return (n % 2) != 0;
}
};
int n = std::count_if(v.begin(), v.end(), IsOdd());
// 모든 데이터가 홀수입니까?
bool b1 = std::all_of(v.begin(), v.end(), IsOdd());
// 홀수인 데이터가 하나라도 있습니까?
bool b2 = std::any_of(v.begin(), v.end(), IsOdd());
// 모든 데이터가 홀수가 아닙니까?
bool b3 = std::none_of(v.begin(), v.end(), IsOdd());
}
// Q4) 벡터에 들어가있는 모든 숫자들에 3을 곱해주세요.
{
for (unsigned int i = 0; i < v.size(); ++i)
{
v[i] *= 3;
}
struct MultiplyBy3
{
void operator()(int& n)
{
n *= 3;
}
};
std::for_each(v.begin(), v.end(), MultiplyBy3());
}
// Q5) 홀수인 데이터를 일괄 삭제
{
for (auto it = v.begin(); it != v.end(); )
{
if ((*it % 2) != 0)
it = v.erase(it);
else
++it;
}
v.clear();
v.push_back(1);
v.push_back(4);
v.push_back(3);
v.push_back(5);
v.push_back(8);
v.push_back(2);
struct IsOdd
{
bool operator()(int& n)
{
return (n % 2) != 0;
}
};
// 기존 : 1 4 3 5 8 2
// 결과 : 4 8 2 5 8 2 (이상한 결과가 나온다는 것을 볼 수 있다)
std::remove_if(v.begin(), v.end(); IsOdd());
// std::remove(v.begin(), v.end(), 4);
// 직접 동작을 까보니
/*
template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
first = std::find_if(first, last, p);
if (first != last)
for (ForwardIt i = first; ++i != last;)
if (!p(*i))
*first++ = std::move(*i);
return first;
}
*/
// 불필요한 데이터를 일일이 삭제하는 것이 아니라
// 필요한 데이터만 남겨두는 것으로 작동하고 있다.
// 리턴해주는 first 데이터는 사용하지 않아야 하는 이터레이터(위치)를 리턴해준다.
// 말 그대로 4 8 2 위치(5) 8 2
// 정리하자면, remove란 이름때문에 삭제해주는 걸로 느껴지는데
// 실질적으로 데이터를 날려주는 부분은 없고,
// 필요한 데이터만 재조정한 후, 사용하지 않는 데이터의 첫 위치를 반환해준다고 보면 된다.
// 그래서 remove만 단독적으로 사용한다기 보다는
// remove와 erase를 같이 사용해서 필요하지 않는 쓰레기 데이터를 지워줘야 한다.
vector<int>::iterator it = std::remove_if(v.begin(), v.end(); IsOdd());
v.erase(it, v.end());
// v.erase(std::remove_if(v.begin(), v.end(); IsOdd()), v.end());
}
}
'[C++] Data Structure & Algorithm > STL' 카테고리의 다른 글
[STL] set, multimap, multiset (0) | 2023.05.20 |
---|---|
[STL] map (1) | 2023.05.19 |
[STL] deque (0) | 2023.05.19 |
[STL] list #2 (0) | 2023.05.19 |
[STL] list #1 (0) | 2023.05.15 |
댓글