unique함수는

https://velog.io/@whipbaek/c-unique-%ED%95%A8%EC%88%98%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC

 

c++ unique() 함수에 관하여

공부하게 된 배경https://programmers.co.kr/learn/courses/30/lessons/12906위 문제를 푸는데 unique와 erase의 조합 한 줄 만으로 해결하는 코드가 있었다. 문제를 풀 때는 생각이 안났으나 두 함수 모두 대강 알

velog.io

의 블로그를 참고하여 작성하였습니다.


unique(구간의 시작값, 구간의 마지막값) ;

-범위내에 인접하는(연속적인) 중복 요소들을 제거해준다.

-정렬 후에 배열의 사이즈가 바뀌지 않음

-배열의 사이즈가 바뀌지 않고 중복요소인 원소들은 뒤로 밀려난다.

-반환값은 중복없이 나열된 마지막 원소 다음의 반복자를 반환한다.

- <algorithm> 헤더를 사용한다.

 

unique함수 하나로는 vector 중복 원소 제거를 하는것은 어렵다.sort()함수를 사용하여 정렬 한 뒤 erase()함수를 활용하여 쓰레기값을 제거해줘야한다. 

 

 

#include<iostream>
#include<vector>
#include<algorithm>

void main()
{
    std::vector<int> v1 = { 10,10,20,30,20,10 };

    std::vector<int>::iterator iter = unique(v1.begin(), v1.end());

    for (int index : v1)
    {
        std::cout << index << " ";
    }
    std::cout << " 반환값 : " << *iter << " " << &iter << std::endl;

    //======================================================

    std::vector<int> v2 = { 10,10,20,30,20,10 };

    sort(v2.begin(), v2.end()); // 10,10,10,20,20,30
    iter = unique(v2.begin(), v2.end());
    for (int index : v2)
    {
        std::cout << index << " ";
    }
    std::cout << " 반환값 : " << *iter << " " << &iter << std::endl;
	
    v2.erase(iter, v2.end());
    // v2.erase(unique(v2.begin(), v2.end()), v2.end());
    //unique와 erase함수를 사용하여 정렬한 vector의 중복된 원소를 제거할 수 있다.  

    for (int index : v2)
    {
        std::cout << index << " ";
    }


    return;
}

 

<출력 결과>

첫번째 결과 : 정렬없이 unique함수를 동작했을때 반환되는 값은 v1[4]의 반복자가 반환된다.

두번째 결과 : 오름차순 정렬 뒤에 unique함수를 동작했을때 10의 원소가 한개씩 20,30으로 변경 되었다. 하지만 의미 중복을 제거하는 것이 목적이기에 의미 없는값들이다. (작동원리는 밑에서 서술)

세번쨰 결과 : v2.erase함수를 범위 : iter(v2[3]) ~ v2.end() 만큼 제거한뒤 출력한 값이다. 

 

<작동 원리>

더보기

위 링크는 첫번째 결과값을 작동원리를 설명했으니 나는 정렬한 두번째 값(10 10 10 20 20 30)으로 설명을 해보겠다.

//unique함수 원문
template <class ForwardIterator>
  ForwardIterator unique (ForwardIterator first, ForwardIterator last)
  {
  if (first==last) return last;

  ForwardIterator result = first;
  while (++first != last)
  {
    if (!(*result == *first))  // or: if (!pred(*result,*first)) for version (2)
      *(++result)=*first;
  }
  return ++result;
}//출처 : https://www.cplusplus.com/reference/algorithm/unique/

  if (first==last) return last;

first iter와 last iter가 같은경우는 원소가 1개 이하라는 뜻이므로 end() 값을 리턴

 

 

first, last , result iter(반복자) 초기화 완료
while 반복문의 함수 동작후 확인, // while문이 참이므로 반복분 시작

while 반복문에 들어와서 

 if (!(*result == *first)) , if조건문이 있는데  result와 first가 같으므로 true에 !를 만나 false를 반환

 

다시 while 반복문의 조건을 확인해서 계속 roop 시키면 ......

result와 first의 값이 달라지는 경우가 발생

 

 if (!(*result == *first)의 true임으로 if문이 동작한다.

*(++result)=*first; 동작 완료시

*first 가 가르키고 있는 20의 data를 result의 다음 반복자(++result)에 data를 정의하는것이다. 

그럼 vector의 [1] index의 data는 10-> 20으로 변경된다. 그리고 이 과정을 while이 false가 나올때까지 반복하게 되면  

중복 되지 않은 원소는 전부 앞으로 정렬하게 되고, 중복된 원소들은 뒤로 밀리게 되며 반환되는 return 값은 현재 가르키고있는 result의 다음 iter 값이 반환된다. 즉, unique함수의 return값은 쓰게기값(중복값)들이 모여있는 첫번째 인덱스를 iter를 반환하게 된다. 

 

이 점을 이용하여 unique한뒤 erase함수로 현재 반환 받은 값에서부터 end() 까지 지워버리면 

10 20 30 만 남게 되는것이다. 

 

+ Recent posts