[STL] Algorithm - 원소 수정x

치치·2025년 7월 15일

STL

목록 보기
15/21
post-thumbnail

Algorithm 알고리즘

📌 원소를 수정하지 않는 알고리즘

#include <algorithm> 헤더를 사용해야 한다.

알고리즘 함수사용 형태 (인자)역할반환값
adjacent_findadjacent_find(first, last)
adjacent_find(first, last, binary_pred)
인접한 동일 원소 또는 조건 만족 쌍 찾기조건 만족하는 첫 번째 반복자, 없으면 last
countcount(first, last, value)주어진 값과 같은 원소 개수 세기일치하는 원소 개수 (int)
count_ifcount_if(first, last, unary_pred)조건을 만족하는 원소 개수 세기조건을 만족하는 개수 (int)
equalequal(first1, last1, first2)
equal(first1, last1, first2, binary_pred)
두 범위가 같은지 비교같으면 true, 아니면 false
findfind(first, last, value)특정 값을 가진 첫 원소 찾기해당 원소의 반복자, 없으면 last
find_iffind_if(first, last, unary_pred)조건 만족 첫 원소 찾기조건 만족 원소 반복자, 없으면 last
find_first_offind_first_of(first1, last1, first2, last2)
find_first_of(first1, last1, first2, last2, binary_pred)
첫 번째 범위에서 두 번째 범위와 일치하는 첫 원소 찾기일치하는 첫 번째 원소 반복자, 없으면 last1
find_endfind_end(first1, last1, first2, last2)
find_end(first1, last1, first2, last2, binary_pred)
첫 번째 범위에서 마지막으로 일치하는 부분 찾기마지막으로 일치하는 부분 시작 반복자
searchsearch(first1, last1, first2, last2)
search(first1, last1, first2, last2, binary_pred)
부분 시퀀스를 찾음부분 시퀀스의 시작 반복자
search_nsearch_n(first, last, count, value)
search_n(first, last, count, value, binary_pred)
동일한 값이 연속된 부분 찾기시작 반복자
for_eachfor_each(first, last, func)각 원소에 함수 적용 (수정은 하지 않음)함수 객체 또는 람다의 복사본 반환
lexicographical_comparelexicographical_compare(first1, last1, first2, last2)
... , comp
두 범위를 사전순으로 비교true or false
minmin(a, b)
min(a, b, comp)
두 값 중 작은 값 반환더 작은 값
maxmax(a, b)
max(a, b, comp)
두 값 중 큰 값 반환더 큰 값
min_elementmin_element(first, last)
min_element(first, last, comp)
가장 작은 원소 찾기최소값 반복자
max_elementmax_element(first, last)
max_element(first, last, comp)
가장 큰 원소 찾기최대값 반복자
mismatchmismatch(first1, last1, first2)
mismatch(first1, last1, first2, binary_pred)
두 범위가 처음 불일치하는 위치 찾기pair<first1_iter, first2_iter>


✅ 참고사항

  • 객체일 때
    변수명.first
pair<string, int> p;
cout << p.first << endl;

---------------------------

  • 반복자일 때
    변수명->first
map<string, int> m;
auto iter = m.begin();
cout << iter->first << endl;


⭐ adjancent_find(반복자 구간);

인접한 동일 원소 또는 조건 만족 쌍 찾기

✅ adjacent_find(구간 반복자);

➡ 현재 원소와 다음 원소가 같아지는 첫 원소의 반복자를 반환한다.

✅ adjacent_find(구간 반복자, 함수 객체);

이항 조건자 버전으로, 현재 원소와 다음 원소가 해당 함수에 적합한 지 확인하고 반환한다.

🟥 찾는 원소가 없다면 구간의 끝 반복자를 반환한다.

ex1) [v.begin(), v.end()) 구간에서 찾고자 하는 원소가 없다면 v.end() 반복자를 반환한다.
ex2) [v.begin(), v.begin() + 3) 구간에서 찾고자 하는 원소가 없다면 v.begin() + 3 반복자를 반환한다.

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

bool Calculate(int a, int b)
{
	return abs(a - b) > 10; // a - b가 10 보다 크다면 true 
}

int main()
{
	// adjacent_find는 찾는 원소가 없으면 구간의 끝 반복자를 반환한다.

	vector<int>v;

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

	vector<int>::iterator iter = adjacent_find(v.begin(), v.end());

	if (iter != v.end())
	{
		cout << *iter << endl; // 결과 : 20
	}

	// -----------------------------

	vector<int>v2;

	v2.push_back(10); // begin()
	v2.push_back(50);
	v2.push_back(60);
	v2.push_back(70); // begin() + 3
	v2.push_back(80);

	vector<int>::iterator iter2 = adjacent_find(v2.begin(), v2.begin() + 3, Calculate);

	if (iter2 != v2.begin() + 3)
	{
		cout << *iter2 << endl; // 결과 : 10
	}
}



⭐count(반복자 구간, 찾을 원소); & count_if()

주어진 값과 같은 원소 개수 세기


✅ count(구간 반복자, 세고자 하는 값);

➡ 세고자 하는 값의 갯수가 int로 반환된다.

✅ count_if(구간 반복자, 세고자 하는 값, 함수 객체);

조건자에 해당하는 원소들을 반환한다.

🟥 찾는 원소가 없다면 int 0을 반환한다.

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

bool Calculate(int n)
{
	return n > 10; // 10보다 크다면 true 반환
}

int main()
{
	vector<int> v;
	
	v.push_back(10);
	v.push_back(10);
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);

	// 원소가 10인 갯수
	int num = count(v.begin(), v.end(), 10);

	cout << num << "개" << endl; // 결과 : 3개

	// ----------------------------------

	vector<int> v2;

	v2.push_back(10);
	v2.push_back(10);
	v2.push_back(10);
	v2.push_back(20);
	v2.push_back(30);

	// 원소가 10인 갯수
	int num2 = count_if(v2.begin(), v2.end(), Calculate);

	cout << num2 << "개" << endl; // 결과 : 2개
}


⭐ equal(1반복자 구간, 2시작 반복자);

두 범위가 같은지 비교
첫번째 순차열은 구간[b, e)를 필요로 하지만, 두번째 순차열은 시작 반복자만 필요로 한다.
두번째 순차열의 범위는 첫번째 순차열의 크기만큼 결정된다.

✅ equal(1구간 반복자, 2구간 시작 반복자);

➡ 두 순차열이 같은 지 확인하고 bool 타입을 반환한다.

✅ equal(1구간 반복자, 2구간 시작 반복자, 함수 객체);

두 순차열의 조건자에 해당하는 원소들이라면 true를 반환한다.

🟥 두 순차열이 같지 않다면 false를 반환한다.

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

bool Calculate(int left, int right)
{
	return abs(left - right) >= 0;
}

int main()
{
	vector<int> v1;
	
	v1.push_back(10);
	v1.push_back(10);
	v1.push_back(10);
	
	vector<int> v2;

	v2.push_back(10);
	v2.push_back(10);
	v2.push_back(10);
	v2.push_back(20);
	v2.push_back(30);

	// [v2.begin() ~ v2.begin()+3) 범위
	bool result = equal(v1.begin(), v1.end(), v2.begin());

	if (result == true)
	{
		cout << "두 순차열이 같습니다1" << endl;
	}

	bool result2 = equal(v1.begin(), v1.end(), v2.begin(), Calculate);

	if (result2 == true)
	{
		cout << "두 순차열이 같습니다2" << endl;
	}
}


⭐ find(반복자 구간, 찾고자 하는 값); & find_if()

특정 값을 가진 첫 원소 찾기

✅ find(구간 반복자, 찾고자 하는 값);

➡ 원하는 구간 안에서 찾고자 하는 값 중 가장 첫 원소의 반복자를 반환한다.

✅ find_if(구간 반복자, 함수 객체);

➡ 원하는 구간 안에서 조건자에 맞는 값 중 가장 첫번째 원소의 반복자를 반환한다.

🟥 만약 찾고자 하는 값이 없다면 구간의 끝 반복자를 반환한다.

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

bool Calculate(int n)
{
	return n > 25; // 25보다 크면 true 반환
}

int main()
{
	vector<int> v;

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

	vector<int>::iterator iter = find(v.begin(), v.end(), 30);

	if (iter != v.end())
	{
		cout << "첫번째 일치 원소의 시작 반복자 : " << *iter << endl;
	}

	vector<int>::iterator iter2 = find_if(v.begin(), v.end(), Calculate);

	if (iter2 != v.end())
	{
		cout << "25보다 큰 원소 중 가장 첫번째 원소 : " << *iter2 << endl;
	}
}


⭐ find_end(1구간 반복자, 2구간 반복자);

첫 번째 범위에서 일치하는 순차열 중 마지막 순차열을 찾는 법 ➡ 순차열이 여러개라면 마지막 순차열의 반복자를 반환한다.

✅ find_end(1구간 반복자, 2구간 반복자);

➡ 1구간의 범위 내에서 2구간의 순차열과 일치하는 것들 중 마지막 순차열의 시작 반복자를 반환한다.
➡ 아래의 코드에서 구간1의 뒷 부분 10, 30이 발견되어 반환된다.

int main()
{
	vector<int> v;

	v.push_back(10); // 일치
	v.push_back(30); // 일치
	v.push_back(10);
	v.push_back(40);
	v.push_back(10); // 일치
	v.push_back(30); // 일치

	vector<int> v2;
	
	v2.push_back(10); 
	v2.push_back(30); 

	vector<int>::iterator iter = find_end(v.begin(), v.end(), v2.begin(), v2.end());

	if (iter != v.end())
	{
		cout << "일치하는 마지막 순차열의 시작 반복자 : " << *iter << endl; // 10
		cout << "시작 반복자의 앞 : " << *(iter-1) << endl; // 40
	}
}

✅ find_end(1구간 반복자, 2구간 반복자, 함수 객체);

➡ 1구간의 범위 내에서 2구간의 원소가 조건에 맞는 것들 중 마지막 순차열의 시작 반복자를 반환한다.
➡ 아래의 코드에서 구간 2보다 작은 순차열들(Calculate가 true인 것들) 중 마지막 순차열의 시작 반복자의 값은 10이다.

bool Calculate(int left, int right)
{
	return left <= right;
}

int main()
{
	vector<int> v;

	v.push_back(10); // 일치
	v.push_back(20); // 일치
	v.push_back(30); // 일치

	v.push_back(10); // 일치 -> 일치하는 마지막 순차열의 시작 반복자
	v.push_back(20); // 일치
	v.push_back(30); // 일치

	vector<int> v2;
	
	v2.push_back(15); 
	v2.push_back(25); 
	v2.push_back(35);


	vector<int>::iterator iter = find_end(v.begin(), v.end(), v2.begin(), v2.end(), Calculate);

	if (iter != v.end())
	{
		cout << "일치하는 마지막 순차열의 시작 반복자 : " << *iter << endl; // 10
		cout << "시작 반복자의 앞 : " << *(iter-1) << endl; // 30
	}
}

🟥 만약 찾고자 하는 값이 없다면 1구간의 끝 반복자를 반환한다.



⭐ search(1구간 반복자, 2구간 반복자);

find_end()와 동일한데 find_end()는 일치하는 마지막 순차열의 반복자를 반환하고, search()는 일치하는 첫번째 순차열의 반복자를 반환한다.

🟥 만약 찾고자 하는 값이 없다면 1구간의 끝 반복자를 반환한다.

int main()
{
	vector<int> v;

	v.push_back(10); // 일치
	v.push_back(30); // 일치
	v.push_back(10);
	v.push_back(40);
	v.push_back(10); 
	v.push_back(30); 

	vector<int> v2;

	v2.push_back(10);
	v2.push_back(30);

	vector<int>::iterator iter = search(v.begin(), v.end(), v2.begin(), v2.end());

	if (iter != v.end())
	{
		cout << "일치하는 처음 순차열의 시작 반복자 : " << *iter << endl; // 10
		cout << "시작 반복자의 뒤 : " << *(iter + 1) << endl; // 30
		cout << "시작 반복자의 뒤 뒤 : " << *(iter + 2) << endl; // 10
	}
}


⭐ search_n(구간 반복자, 연속 횟수, 찾고자 하는 값);

✅ search_n(구간 반복자, 연속 횟수, 찾고자 하는 값);

➡ 아래의 코드에서 3, 30이면 30의 값이 3번 반복되는 순차열을 찾고 그 순차열의 시작 반복자를 반환한다.

✅ search_n(구간 반복자, 연속 횟수, 찾고자 하는 값, 함수 객체);

➡ 아래의 코드에서 찾고자 하는 값과 순차열들의 값의 조건이 맞고 3번 반복된다면 그 순차열의 시작 반복자를 반환한다.

🟥 만약 찾고자 하는 값이 없다면 1구간의 끝 반복자를 반환한다.

bool Calculate(int a, int b)
{
	return abs(a - b) <= 5; // 5이하라면 true 반환
}


int main()
{
	vector<int> v;

	v.push_back(10); 
	v.push_back(31); 
	v.push_back(31);
	v.push_back(31);
	v.push_back(10); 
	v.push_back(10); 

	// 30과의 차이가 5 이하면서 3번 연속되는 순차열의 시작 반복자를 반환 
	vector<int>::iterator iter = search_n(v.begin(), v.end(), 3, 30, Calculate);

	cout << "찾은 순차열 시작 반복자 : " << *iter << endl;     // 31
	cout << "찾은 순차열 이전 반복자 : " << *(iter-1) << endl; // 10
}


⭐ find_first_of(1구간 반복자, 2구간 반복자);

첫 번째 범위에서 두 번째 범위와 일치하는 첫 원소 찾기

✅ find_first_of(1구간 반복자, 2구간 반복자);

➡ 1구간의 범위 내에서 2구간의 원소 중 가장 먼저 발견된 원소의 시작 반복자를 반환한다.
➡ 아래의 코드에서 구간 2에 있는 값들 중 구간1의 10이 제일 먼저 발견되었다.

✅ find_first_of(1구간 반복자, 2구간 반복자, 함수 객체);

➡ 1구간의 범위 내에서 2구간의 원소 보다 큰 값의 시작 반복자를 반환한다.
➡ 아래의 코드에서 구간 2에 있는 값들 중 구간1의 20이 제일 먼저 구간2보다 큰 값으로 발견되었다.

🟥 만약 찾고자 하는 값이 없다면 1구간의 끝 반복자를 반환한다.

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

bool Calculate(int left, int right)
{
	return left > right; // v1 > v2인 순차열들은 모두 true를 반환
}

int main()
{
	vector<int> v;

	v.push_back(10); 
	v.push_back(20); 
	v.push_back(30); 
	v.push_back(40);

	vector<int> v2;
	
	v2.push_back(30); 
	v2.push_back(20); 
	v2.push_back(10);


	vector<int>::iterator iter = find_first_of(v.begin(), v.end(), v2.begin(), v2.end());

	if (iter != v.end())
	{
		cout << "가장 먼저 발견된 원소의 시작 반복자 : " << *iter << endl; // v1 = 10
		
		// left 순차열에서 right 값 중 가장 먼저 발견된 원소의 시작 반복자를 반환한다.
	}

	vector<int>::iterator iter2 = find_first_of(v.begin(), v.end(), v2.begin(), v2.end(), Calculate);

	if (iter2 != v.end())
	{
		cout << "함수객체가 true이면서 가장 먼저 발견된 원소의 시작 반복자 : " << *iter2 << endl; // v1 = 20

		// left 순차열에서 right의 값들보다 큰 값의 시작 반복자를 제일 먼저 반환한다. 
		// -> v1의 20은 v2의 10보다 크다.
	}
}


⭐ for_each(반복자 구간, 함수 객체);

각 원소에 함수 적용 (수정은 하지 않음)

void Print(int n)
{
	cout << n << " ";
}

class PrintFunctor
{
	char fmt;

public:
	explicit PrintFunctor(char c = ' ') :fmt(c) { }
	void operator () (int n) const
	{
		cout << n << fmt;
	}
};

int main()
{
	vector<int> v;

	v.push_back(10); 
	v.push_back(20); 
	v.push_back(30); 
	v.push_back(40);

	for_each(v.begin(), v.end(), Print);

	cout << '\n';

	for_each(v.begin(), v.end(), PrintFunctor(','));
}


⭐ lexicographical_compare(1구간 반복자, 2구간 반복자);

두 범위를 사전순으로 비교

✅ lexicographical_compare(1구간 반복자, 2구간 반복자);

✅ lexicographical_compare(1구간 반복자, 2구간 반복자, 함수 객체);

🟥 true / false를 반환한다.

template<typename T>
struct Less
{
	bool operator() (const T& left, const T& right) const
	{
		return left < right;
	}
};

int main()
{
	vector<int>v1;

	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);

	vector<int>v2;

	v2.push_back(10);
	v2.push_back(30);
	v2.push_back(30);

	vector<int>v3;

	v3.push_back(10);
	v3.push_back(25);
	v3.push_back(30);

	// 두 범위를 사전적으로 비교해서, 첫번째 범위가 두 번째보다 사전순으로 앞서면 true,
	// 아니면 false를 반환합니다.

	// default = less<int>()
	if (lexicographical_compare(v1.begin(), v1.end(), v2.begin(), v2.end()))
	{
		cout << "v1 < v2" << endl; // v2가 사전순으로 앞선다. (오름차순)
	}

	// greater<int>()
	if (lexicographical_compare(v1.begin(), v1.end(), v2.begin(), v2.end(), greater<int>()))
	{
		cout << "v1 < v2" << endl;
	}
	else
	{
		cout << "v1 > v2" << endl; // v1이 사전순으로 앞선다. (내림차순)
	}

	// 사용자 정의 함수 객체
	if (lexicographical_compare(v1.begin(), v1.end(), v2.begin(), v2.end(), Less<int>()))
	{
		cout << "c1 < v2" << endl;// v2가 사전순으로 앞선다. (오름차순)
	}
	
}

⭐ min() , max ()

두 값 중 작은값 & 큰 값을 반환한다. ➡ 사용자 정의 함수 객체 가능

✅ 일반 변수 a, b 2개 비교

int main()
{
	int a = 10; int b = 20;
	int r;

	r = max(a, b);

	cout << "max값 : " << r << endl; // 20

	r = min(a, b);

	cout << "min값 : " << r << endl; // 10
}

✅ 사용자 정의 함수 객체를 사용한 비교

class Point
{
	int x, y;

public :
	// 생성자 생성 & 초기화 (입력받은 x, y를 할당한다.)
	Point(int _x = 0, int _y = 0) : x(_x), y(_y) { }

	int GetX() const { return x; }
	int GetY() const { return y; }

	void Print() const { cout << '(' << x << ',' << y << ')' << endl; }
};

bool XCompare(const Point& left, const Point& right) // x값만 비교
{
	return left.GetX() < right.GetX();
}

bool YCompare(const Point& left, const Point& right) // y값만 비교
{
	return left.GetY() < right.GetY();
}

int main()
{
	Point pt1(5, 8);
	Point pt2(3, 9);
	Point pt3; // (0, 0)

	pt3 = max(pt1, pt2, XCompare);

	cout << "X max값 : "; pt3.Print();
	
	pt3 = max(pt1, pt2, YCompare);

	cout << "Y max값 : "; pt3.Print();
}

✅ 여러개 중 min / max 판별

모든 인자 타입이 동일하다면 여러 변수에서 최소 / 최대값을 구할 수 있다.

int main() 
{
    int a = 5, b = 2, c = 9, d = 3;

    int minimum = std::min({a, b, c, d});
    int maximum = std::max({a, b, c, d});

    cout << "min: " << minimum << "\n";  // 2
    cout << "max: " << maximum << "\n";  // 9
}

💯 예시) 프로그래머스_직사각형 넓이 구하기

최대, 최소값을 찾을 때, 모든 타입이 int인 2차원 배열의 값을 {a, b, c, d} 형태로 인자에 넣었다.

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

int solution(vector<vector<int>> dots) 
{
    int num1 = max({dots[0][0], dots[1][0], dots[2][0], dots[3][0]});
    int num2 = min({dots[0][0], dots[1][0], dots[2][0], dots[3][0]});
    
    int num3 = max({dots[0][1], dots[1][1], dots[2][1], dots[3][1]});
    int num4 = min({dots[0][1], dots[1][1], dots[2][1], dots[3][1]});

    return (num1 - num2) * (num3 - num4);
}

⭐ min_element() & max_element()

최소값의 반복자 & 최대값의 반복자를 반환한다.

✅ min_element(구간 반복자);

✅ max_element(구간 반복자);

int main()
{
	vector<int>v;

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

	vector<int>::iterator iter1 = max_element(v.begin(), v.end());
	vector<int>::iterator iter2 = min_element(v.begin(), v.end());

	cout << "범위 내 가장 큰 원소 : " << *iter1 << endl;
	cout << "범위 내 가장 작은 원소 : " << *iter2 << endl;
}
class Point
{
	int x, y;

public :
	// 생성자 생성 & 초기화 (입력받은 x, y를 할당한다.)
	Point(int _x = 0, int _y = 0) : x(_x), y(_y) { }

	int GetX() const { return x; }
	int GetY() const { return y; }

	void Print() const { cout << '(' << x << ',' << y << ')' << endl; }
};

bool Compare(const Point& left, const Point& right)
{
	// X값 먼저 비교 후 Y값 비교
	if (left.GetX() < right.GetX())
	{
		return true;
	}
	else if (left.GetX() > right.GetX())
	{
		return false;
	}
	else // X값이 같다면 Y값으로 비교
	{
		return left.GetY() < right.GetY();
	}
}

int main()
{
	vector<Point>v;

	v.push_back(Point(3, 2));
	v.push_back(Point(2, 5));
	v.push_back(Point(1, 5));
	v.push_back(Point(3, 3));
	v.push_back(Point(3, 2));

	vector<Point>::iterator iter = max_element(v.begin(), v.end(), Compare);

	// 동일한 의미의 값 접근법
	cout << "max :"; iter->Print(); cout << endl;

	cout << "max :"; (*iter).Print(); cout << endl;


}

mismatch(구간 반복자, 시작 반복자);

두 범위가 불일치하는 처음 순차열 찾기 ➡ 반복자 쌍을 반환한다. pair<first_iter, second_iter>

✅ mismatch(1구간 반복자, 2구간 시작 반복자);

➡ 반복자 쌍이 반환되기 때문에 타입은 pair로 반환된다.

✅ mismatch(1구간 반복자, 2구간 시작 반복자, 함수 객체);

함수 객체가 false를 반환하는 것이 mismatch에서는 조건에 맞는 답이다.

bool Calculate(int a, int b)
{
	return abs(a - b) < 10; // 두 값의 차가 10미만이면 true반환
}
// mismatch는 false를 반환하는 것을 찾는다.

int main()
{
	vector<int>v1;

	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);

	vector<int>v2;

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

	pair<vector<int>::iterator, vector<int>::iterator> p;

	// v2는 v1의 크기만큼 끝 반복자
	p = mismatch(v1.begin(), v1.end(), v2.begin());

	// 처음 발견된 서로 다른 원소의 반복자 쌍을 반환
	cout << "v1 : " << *p.first << endl;  // 30
	cout << "v2 : " << *p.second << endl; // 50

	// -----------------------------------

	pair<vector<int>::iterator, vector<int>::iterator> p2;

	p2 = mismatch(v1.begin(), v1.end(), v2.begin(), Calculate);
	
	// fasle를 반환하는 30, 50 반복자 쌍이 반환된다.
	cout << "v1 : " << *p2.first << endl;  // 30
	cout << "v2 : " << *p2.second << endl; // 50
}
profile
뉴비 개발자

0개의 댓글