C++STL中的unique函數解析


一.總述

  unique函數屬於STL中比較常用函數,它的功能是元素去重。即”刪除”序列中所有相鄰的重復元素(只保留一個)。此處的刪除,並不是真的刪除,而是指重復元素的位置被不重復的元素給占領了(詳細情況,下面會講)。由於它”刪除”的是相鄰的重復元素,所以在使用unique函數之前,一般都會將目標序列進行排序。

二.函數原型

unique函數的函數原型如下:

1.只有兩個參數,且參數類型都是迭代器:

 

iterator unique(iterator it_1,iterator it_2);

 

這種類型的unique函數是我們最常用的形式。其中這兩個參數表示對容器中[it_1,it_2)范圍的元素進行去重(注:區間是前閉后開,即不包含it_2所指的元素),返回值是一個迭代器,它指向的是去重后容器中不重復序列的最后一個元素的下一個元素

2.有三個參數,且前兩個參數類型為迭代器,最后一個參數類型可以看作是bool類型:

iterator unique(iterator it_1,iterator it_2,bool MyFunc);

該類型的unique函數我們使用的比較少,其中前兩個參數和返回值同上面類型的unique函數是一樣的,主要區別在於第三個參數。這里的第三個參數表示的是自定義元素是否相等。也就是說通過自定義兩個元素相等的規則,來對容器中元素進行去重。這里的第三個參數與STL中sort函數的第三個參數功能類似(關於sort函數:http://www.cnblogs.com/wangkundentisy/p/8982180.html)。關於第三個參數的詳細介紹,可以參考:http://www.cplusplus.com/reference/algorithm/unique/

三.函數用法實例

  上面介紹了unique函數的功能和原型,那么,它到底是如何進行去重的呢?即“刪除”的具體操作是怎樣的呢?

關於這個問題,http://www.cplusplus.com/reference/algorithm/unique/給了我們一種解釋,即unique函數是完全等價於下面這個函數的:

iterator My_Unique (iterator first, iterator last)
{
  if (first==last) return last;

  iterator result = first;
  while (++first != last)
  {
    if (!(*result == *first))  
      *(++result)=*first;
  }
  return ++result;
}

分析這段代碼,我們可以知道,unique函數的去重過程實際上就是不停的把后面不重復的元素移到前面來,也可以說是用不重復的元素占領重復元素的位置。有了這段代碼我們可以結合實例來更好的理解這個函數了。

實例:

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

static bool myfunc(int i, int j)
{
    return (i + 1) == j;
    //return i == j;
}
int main()
{

    vector<int> a = {1,3,3,4,5,6,6,7};
    vector<int>::iterator it_1 = a.begin();
    vector<int>::iterator it_2 = a.end();

    //sort(it_1,it_2);
    cout<<"去重前的 a : ";
    for(int i = 0 ; i < a.size(); i++)
        cout<<a[i];
    cout<<endl;
    //it_h = unique(it_1,it_2);
    //unique(it_1,it_2,myfunc);
    unique(it_1,it_2);
    cout<<"去重后的 a : ";
    for(int i = 0 ; i < a.size(); i++)
        cout<<a[i];
    cout<<endl;
}

  

運行結果如下:

對於上面的結果,我們可以看到,容器中不重復的元素都移到了前面,至於后面的元素,實際上並沒有改變(這個過程只需結合My_Unique函數來分析即可)。

注:

1.有很多文章說的是,unique去重的過程是將重復的元素移到容器的后面去,實際上這種說法並不正確,應該是把不重復的元素移到前面來。

2.一定不要忘記的是,unique函數在使用前需要對容器中的元素進行排序(當然不是必須的,但我們絕大數情況下需要這么做),由於本例中的元素已經是排好序的,所以此處我沒排序,但實際使用中不要忘記。

四.用法拓展

 1.我們以上的實例針對的是函數原型1的用法,對於函數原型2,我們仍然使用上述實例,只不過unique的用法變成:

unique(it_1,it_2,myfunc);

即自定義的元素相等的准則,其中myfunc在上述實例中有其源碼,分析可知,只有i+1 == j的時候我們才認為i和j“相等”;實例結果如下:

也就是說,按照我們自定義的規則,這個實例中只有3和4”相等的”,4和5是”相等的”,5和6,6和7是”相等的”。所以最終結果是上圖的樣子。

2.unique函數通常和erase函數一起使用,來達到刪除重復元素的目的。(注:此處的刪除是真正的刪除,即從容器中去除重復的元素,容器的長度也發生了變換;而單純的使用unique函數的話,容器的長度並沒有發生變化,只是元素的位置發生了變化)關於erase函數的用法,可以參考:http://www.cnblogs.com/wangkundentisy/p/9023977.html。下面是一個具體的實例:

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

int main()
{

    vector<int> a ={1,3,3,4,5,6,6,7};
    vector<int>::iterator it_1 = a.begin();
    vector<int>::iterator it_2 = a.end();
    vector<int>::iterator new_end;

    new_end = unique(it_1,it_2); //注意unique的返回值
    a.erase(new_end,it_2);
    cout<<"刪除重復元素后的 a : ";
    for(int i = 0 ; i < a.size(); i++)
        cout<<a[i];
    cout<<endl;

}

運行結果如下:

可以看到,相比之前的結果,a的長度確實發生了改變,真正的刪除了a中的重復元素。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM