引言
今天做题目时,遇到一个操作是:去除有序的一段序列里重复的元素,那直接扫一遍就可以了。在看别人代码时发现了unique()这个函数,正如他的名字一样,“独一无二”,可以方便地完成这个操作。
STL定义
_FwdIt unique(_FwdIt _First, _FwdIt _Last)
template<class _FwdIt,
class _Pr> inline
用法
unique()函数将重复的元素”折叠”,使成唯一
看一个demo
//demo1
int main()
{
string str="wjmzbmrbb";
unique(str.begin(),str.end());
cout<<str<<endl;
return 0;
//output:wjmzbmrbb
}
咦,为什么m有两个但为什么没有折叠呢?
unique()是剔除重复的没错,可是他是剔除相邻之间字符重复的
咦,那bb怎么没剔除?
再看一个demo
//demo2
int main()
{
string str="bbwerjj";
unique(str.begin(),str.end());
cout<<str<<endl;
return 0;
//output:bwerjjj
}
不仅没有剔除还多了一个j?
实际上,unique()函数并不是真的在源字符串上进行剔除的,原来的字符串经过unique()函数后虽然除掉了相邻之间重复的字符,可是字符串长度是不变的,也就是说所占内存大小没变。
那有没有办法我只要一个串的字符集?排序一下就好
//demo3
int main()
{
string str="wjmzbmrbb";
unique(str.begin(),str.end());
cout<<str<<endl;
sort(str.begin(),str.end());
unique(str.begin(),str.end());
cout<<str<<endl;
return 0;
//output:wjmzbmrbb
// bjmrwzrwz
}
排序后我们就让相同的元素相邻了,现在怎么方便取出呢?
unique()函数的返回值是源字符串中去除相邻之间相同字符后剩下的字符串中的最后一个字符的下一个位置.
举例说明:”bwjrbmr”排好序后为”bbjmrrw”,有7个字符,相邻之间重复的有两个,”“被unique()后的字符串面貌是”bjmrwXX”,X代表的是不确定的字符。
unique函数的返回值是一个迭代器类型,指向的是第一个X所处的位置。
STL中的参数区间都是左闭右开的,str.end()返回的迭代器指向第二个X位置的后面一个位置,所以可以调用str.erase()把后两个不确定的字符XX删除掉了。最后得到的就是我们最开始想要的结果了”bjmrw”,即”bwjrbmr”的字符集。
//demo4
int main()
{
string str="bwjrbmr";
sort(str.begin(),str.end());
cout<<str<<endl;
str.erase(unique(str.begin(), str.end()), str.end());
cout<<str<<endl;
return 0;
//output:bbjmrrw
// bjmrw
}
相关函数
上面所展示的是把获取的字符集存储在了原字符串变量中,如果遇到要把字符集放置在额外的变量中的情况,就要用到unique_copy()函数了
直接看demo
//demo5
int main()
{
string str="bwjrbmr";
string tmp;
tmp.resize(str.size());
sort(str.begin(),str.end());
tmp.resize(unique_copy(str.begin(),str.end(),tmp.begin()) - tmp.begin());
cout<<tmp<<endl;
return 0;
//output:bjmrw
}
tmp是存储字符集的目标串,str是原字符串变量。tmp在用之前必须要先设置大小,否则到unique_copy()的时候会报内存错误,因为是要存储字符串的字符集,所以tmp设置和源字符串相同的大小是完全可以的。
最后再把剩余的位置erase掉就好了(这里的erase就是resize了,unique-copy函数返回和unique一样位置的迭代器,再减去tmp.begin()就成了resize的大小,实际上就是在做erase)。