지나공 : 지식을 나누는 공간

벡터의 i번째 요소(중간요소) 실수 없이 삭제하기 - C++ 본문

Algorithm/C++ 노트

벡터의 i번째 요소(중간요소) 실수 없이 삭제하기 - C++

해리리_ 2020. 5. 15. 16:07

나무 재테크 문제에서 제가 푼 방식처럼, 벡터의 중간 원소를 삭제하되, 빠짐 없이 모든 요소를 체크해야 할 때가 있습니다. 그럴 때 잊지 말아야 하는 것이 인덱스 값의 변경입니다. 

 

vector<int>v;
	v.push_back(3); v.push_back(6); v.push_back(5);
	v.push_back(9); v.push_back(2);
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << "체크완료, ";
		if (v[i] == 5) {
			v.erase(v.begin() + i);
			i--;
		}
		cout << endl;
	}
    
	for (int i = 0; i < v.size(); i++)
		cout << v[i]<<" ";

 

위 코드는 main함수는 생략하고 수행하는 부분만 간략히 나타낸 코드입니다.

v벡터에 {3,6,5,9,2} 다섯 개의 원소가 들어있지요.

위 코드의 의도는, 벡터의 모든 요소 5개를 빠짐없이 체크하고, 그 중 5인 요소를 벡터에서 제거하는 것입니다.

 

i번째 요소를 삭제하는 것은 v.erase(begin()+i)를 통해 구현이 가능합니다.

erase()함수는 요소를 삭제하면서 벡터의 크기도 삭제된 만큼 줄여주는 친절한 메소드입니다.

 

위 코드에서 i--; 를 주석처리한 결과와 실행시킨 결과를 비교할 겁니다.

 

1.  i--;를 하지 않은 결과 : 5는 잘 삭제되지만 다섯 개 모든 요소에 대한 체크가 되지 않음. 9를 체크하지 않았음.

 

2. i--를 한 결과 : 5는 잘 삭제되고 모든 요소에 대한 체크도 진행됨.

이런 현상이 발생하는 이유는 아래 그림과 같습니다.

참고로, v.begin()과 v.end()는 벡터 컨테이너의 iterator(반복자)를 반환합니다.

iterator(반복자)는, 포인터와 비슷하게 위치와 관련된 객체입니다.

begin()은 맨 앞 요소의 앞인 시작점을, end()는 맨 끝 요소의 뒤인 끝점을 가리키지요. 

 

아래 그림처럼, 중간원소를 삭제하면 인덱스가 앞으로 당겨집니다.

인덱스 2의 요소인 '5'를 삭제하려고 조건검사를 한 다음, i가 2 일때 요소를 삭제하지요.

이때, 요소가 삭제되었으므로 i가 2일때의 위치는 '9'의 위치와 같습니다.

그 상태에서 바로 for문의 i++이 실행되어버리면, 9가 아닌 다음 요소 2를 체크하게 됩니다.

즉, 삭제된 요소 바로 다음에 위치한 요소는 체크를 못하는 것이지요.

 

따라서, for문에서 모든 원소에 대해 조건만족을 검사하려면 중간 요소 삭제 후 i--;를 통해 인덱스 값을 조정해야 합니다.

 

수정할 부분이나 이해가 안되시는 부분이 있으면 댓글로 남겨주세요. :-)

728x90
Comments