본문으로 바로가기

[C++]벡터 중복제거(sort,unique,erase)

category C++ 2018. 5. 21. 10:16


벡터에서 중복 원소제거가 필요할 때가 있습니다.


그럴때 sort,unique,erase 의 기능을 적절히 활용하여 중복원소를 제거 할 수 있습니다.


먼저 백터하나를 만든뒤 데이터를 막넣습니다. (algorithm 을 include 해주어야합니다 sort와 unique 사용을위해)

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

vector<int> s;

int main()
{
	s.push_back(1);
	s.push_back(2);
	s.push_back(1);
	s.push_back(3);
	s.push_back(2);
	s.push_back(1);
	s.push_back(2);
	
	printf("막넣은 백터s\n");
	for(int i=0;i<s.size();i  )
		cout<<s[i]<<"\t";
	printf("\n\n");
}
막넣은 백터s
1       2       1       3       2       1       2

그리고 바로 unique 를 해봅니다.

	printf("바로 unique(s.begin(),s.end());\n");
	unique(s.begin(),s.end());	
	for(int i=0;i<s.size();i  )
		cout<<s[i]<<"\t";
	printf("\n\n");
바로 unique(s.begin(),s.end());
1       2       1       3       2       1       2

바로 unique를 하게되면 아무런 변화가 없습니다.


이유는 unique는 연속된 중복 원소를 vector의 제일 뒷부분으로 쓰레기값으로 보내버립니다.


이를 확인하기위해 sort를 이용하여 vector를 정렬한뒤 unique를 해보겠습니다.

	printf("정렬 sort(s.begin(), s.end());\n");
	sort(s.begin(), s.end());
	for(int i=0;i<s.size();i  )
		cout<<s[i]<<"\t";
	printf("\n\n");
정렬 sort(s.begin(), s.end());
1       1       1       2       2       2       3
	printf("정렬후 unique(s.begin(),s.end());\n");
	unique(s.begin(),s.end());	
	for(int i=0;i<s.size();i  )
		cout<<s[i]<<"\t";
	printf("\n\n");
정렬후 unique(s.begin(),s.end());
1       2       3       2       2       2       3

정렬을 한 뒤 unique를하니 중복원소인 1,1,2 가 맨뒤로 옮겨졌는데요 이때 1,1,2 그대로 옮겨진것이아니라 2,2,3으로 옮겨졌습니다. 이는 c++ 레퍼런스를 봐도 뒤에 ? ? ? 로 알 수 없는 값이 붙는거 처럼 나와있는데요 정확한 이유를 아시는분은 알려주세요 ㅜㅜ 저도 많이 궁금합니다.


C++ unique reference

  int myints[] = {10,20,20,20,30,30,20,20,10};           // 10 20 20 20 30 30 20 20 10
  std::vector<int> myvector (myints,myints 9);

  // using default comparison:
  std::vector<int>::iterator it;
  it = std::unique (myvector.begin(), myvector.end());   // 10 20 30 20 10 ?  ?  ?  ?


다음은 erase 로 뒤에붙은 쓰레기값을 제거해주면 백터의 중복원소를 제거하는데 성공합니다. 

unique가 끝났으면 반환되는값은 vector의 쓰레기값의 첫번째 위치가 되는데요, 이때문에 바로 unique후 erase가 가능합니다.

	printf("백터.erase(unique(s.begin(),s.end()),s.end())\n");
	s.erase(unique(s.begin(),s.end()),s.end());
	for(int i=0;i<s.size();i  )
		cout<<s[i]<<"\t";
	printf("\n\n");
백터.erase(unique(s.begin(),s.end()),s.end())
1       2       3

이렇게 vector의 중복원소를 제거하는 방법에대해 알아보았습니다.




int형이아닌 문자도 중복제거가 가능합니다.

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

vector<string> s;

int main()
{
	s.push_back("a");
	s.push_back("b");
	s.push_back("a");
	s.push_back("c");
	s.push_back("b");
	s.push_back("a");
	s.push_back("b");
	
	printf("막넣은 백터s\n");
	for(int i=0;i<s.size();i  )
		cout<<s[i]<<"\t";
	printf("\n\n");
	
	printf("정렬 sort(s.begin(), s.end());\n");
	sort(s.begin(), s.end());
	for(int i=0;i<s.size();i  )
		cout<<s[i]<<"\t";
	printf("\n\n");

	printf("백터.erase(unique(s.begin(),s.end()),s.end())\n");
	s.erase(unique(s.begin(),s.end()),s.end());
	for(int i=0;i<s.size();i  )
		cout<<s[i]<<"\t";
	printf("\n\n");
}
막넣은 백터s
a       b       a       c       b       a       b
정렬 sort(s.begin(), s.end());
a       a       a       b       b       b       c
백터.erase(unique(s.begin(),s.end()),s.end())
a       b       c