C++STL中unique函数详解(源码之前——了无秘密)
源码之前——了无秘密。
C++STL中unique函数详解(源码之前——了无秘密)
-
总结
unique函数是属于STL中比较常用的函数,因为我们如果用的存储结构不是set容器,或者说我们想主动进行元素去重,那么unique函数就可以帮到我们,它的作用自然就是元素去重,即“删除”序列中的所有相邻的重复元素(只保留一个)。注意我们这里的“删除”并不是真的删除,只是用不重复元素顶替重复元素,假设有一个已经排好序了的 n n n个元素的容器,现其中有 k k k个不重复元素,那么经过unique函数处理后前k个元素是不重复的元素,后面的 ( n − k ) (n-k) (n−k)个元素与原来的容器中是相同的,我们只对前面进行了操作,也就是说前面的重复元素都被后面的不重复元素顶替了。这一定要理解。由于它“删除”的相邻的重复元素,所以我们在使用unique函数之前,一定要先排好序。
-
函数原型
iterator unique(iterator it_1,iterator it_2,bool MyFunc);
参数列表中前两个参数都是迭代器,表示对区间
[it_1,it_2)
内进行去重。(区间为左闭右开,很多STL函数都是这样)。那最后一个是什么呢?就是我们自定义的元素是否相等函数对象。那什么时候需要定义呢?就是你想认为元素之间应该怎样才算相等的时候定义。不一定要i==j
,我也可以定义相等的含义为i+1==j
,这是都可以的。返回值是指向最后一个元素的下一个元素的迭代器。 -
理解本质
我们来看unique函数的定义,仔细理解它为什么能实现这样的功能,这是关键。
template <class ForwardIterator>
ForwardIterator unique (ForwardIterator first, ForwardIterator last)
{
//这里隐藏了第三个参数,则使用系统默认的相等机制。
if (first==last) return last;//判断是否相等,若相等,则表示数组为空。
ForwardIterator result = first;//利用result迭代器去实现功能。
while (++first != last)//开始遍历区间[first,last)
{
//注意first和result,它们都在变,形成一个同步的取缔,其中first一直往后寻找不重复的元素,而result停留在重复的元素等待取缔。仔细理解下面这个if语句。退出循环时也就遍历完成,此时result指向的是最后一个不重复元素。
if (!(*result == *first)) // or: if (!pred(*result,*first)) for version (2)
*(++result)=*first;
}
return ++result;//这里++,我们返回的就是最后一个不重复元素的下一个迭代器。
}
通过理解完函数定义,我想我们对unique函数的功能和作用摸得也足够清了吧。
-
配合erase函数真正删除元素
我们在前面特别强调过unique函数并不会真正删除元素,而是用替代的方法来实现。容器的大小是不会变得,那么我们如果想真正删除元素我们该怎么办呢?我们想想,unique函数的返回值是指向最后一个不相等的元素的下一个元素的迭代器,我们只要接收这个返回值,利用erase函数把后面元素都给直接删除即可。
-
函数用法实例
测试代码:
/*
*邮箱:unique_powerhouse@qq.com
*blog:https://me.csdn.net/hzf0701
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*
*/
#include<bits/stdc++.h> //POJ不支持
#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair
using namespace std;
const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e5;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//
bool MyFunc(int i,int j){
return i+1==j;//我们这里自定义相等规则为i+1==j。
}
int main(){
//freopen("in.txt", "r", stdin);//提交的时候要注释掉
IOS;
int nums[]={1,1,2,3,3,4,5,7,7,8,8,9,9};//这里我已经排好序了,如果没有排好序一定要排序。
int len=sizeof(nums)/4;
vector<int> temp1(nums,nums+len);
vector<int> temp2(temp1);
cout<<"去重前容器中的元素"<<endl;
rep(i,0,len-1){
cout<<temp1[i]<<" ";
}
cout<<endl;
unique(temp1.begin(),temp1.end());
unique(temp2.begin(),temp2.end(),MyFunc);
cout<<"使用两个参数(默认相等规则)的unique去重后的容器元素。"<<endl;
rep(i,0,len-1){
cout<<temp1[i]<<" ";
}
cout<<endl;
cout<<"使用三个参数(自定义相等规则)的unique去重后的容器元素。"<<endl;
rep(i,0,len-1){
cout<<temp2[i]<<" ";
}
return 0;
}
测试结果:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!