본문 바로가기
[C++] Data Structure & Algorithm/STL

[STL] algorithm

by song.ift 2023. 5. 22.

기존 문제점

  • 예제를 하나씩 풀어봤는데, 가독성이 좋지 않다는 걸 알 수 있다. 코드는 굉장히 단순하지만, 그래도 분석하는데 최소 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

댓글