20170820_C++库函数中unique()和unique_copy()和sort()函数的用法
转自:http://blog.youkuaiyun.com/zlhy_/article/details/8784553
1、在C++中如何使用STL和Algorithm库中的函数一起来获取一个字符串包含的字符集呢?这是今天遇到的问题。
要用到的容器或函数有:string,sort( ),unique( ),unique_copy( )。
2、string:C++中 char * 的代替者,使用它处理字符串的时候再也不用考虑内存访问异常或是下标越界问题了。关于string的用法网上很多,给出一个链接两个链接:
- http://www.byvoid.com/blog/cpp-string/
- http://www.cppblog.com/xulina/articles/36542.html
3、unique( ) 函数是将重复的元素折叠缩编,使成唯一。
unqiue_copy( ) 函数是将重复的元素折叠缩编,使成唯一,并复制到他处。这两个函数的剔除字符原理是:看当前字符与它的前一个字符是否相同,如果相同,就剔除当前字符,如果不同,就跳转到下一个字符。所以在求一个字符串的字符集的时候要先把字符串排个序再调用上面两个函数剔除重复字符,获取字符集。
(1)比如:
string str = "zhaohaoyang";
vector<char> vecch(str.begin(), str.end()); //根据迭代器的起始位置和终止位置来定初始化一个容器
vector<char>::iterator it = vecch.begin();
for (; it != vecch.end(); ++it)
{
cout<<*it;
}
cout<<endl; //输出:zhaohaoyang
(2)
再加上下面两行:
unique(str.begin(), str.end());
out<<str<<endl; //输出的还是原样:zhaohaoyang
这是为什么呢?
分析:
- unique( ) 是剔除重复的元素没错,可是,它是剔除相邻之间字符重复的,str 中的字符前后之间是没有重复的,所以unique 函数是起不到作用的。
-
假如把 str 换成 "acttacct" 执行上面的两句代码结果是:actactct,这个结果也是奇怪的。 按照意愿应该是把多于的 t 与多于的 c 剔掉后只剩下 actact 了啊。 最后两个字符 ct 是怎么回事呢? 因为 unique( ) 函数并不是真的在源字符串上进行剔除的,原来的字符串经过 unique( ) 函数后虽然除掉了相邻之间重复的字符,可是字符串长度是不变的,也就是说所占内存大小没变。
-
遇到这个问题,通常会这么做 str.erase( unique( str.begin(), str.end() ), str.end() );
-
unique( ) 函数的返回值是源字符串中去除相邻之间相同字符后剩下的字符串中的最后一个字符的下一个位置,举例说明:" acttacct "有8个字符,相邻之间重复的有两个," acttacct " 被 unique( ) 后的字符串面貌:是 "actactXX",X代表的是不确定的字符。
-
unique 函数的返回值是一个迭代器类型,指向的是第一个 X 所处的位置。
-
STL中的参数区间都是左闭右开的,str.end() 返回的迭代器指向第二个X位置的后面一个位置,所以调用str.erase() 后就把后两个不确定的字符 XX 删除掉了。最后得到的就是我们最开始想要的结果了"actact"。
4、以上展示还未用的 sort( ) 排序函数。现在来看 sort( ) 的加入会有什么新的变化。
前面说到 unique( ) 和 unique_copy( ) 函数都是针对相邻之间相同字符的剔除,它们并不会从一个字符串的整体去剔除重复字符,如果不用 sort( ) 函数,那么我们想要获取一个字符串所包含的的字符集并不是每一次都能保证正确的(如果字符串中没有相同的字符就是正确的,如果相同的字符都是在相邻位置出现结果也是正确的,但大多数情况下却不是这么回事)。
5、看例子:
string str = "zhaohaoyang";
vector<char> vecch(str.begin(), str.end());
sort(str.begin(), str.end()); //先进行排序,
str.erase( unique(str.begin(), str.end()), str.end() ); //再进行unique 调用,再调用 erase 函数 删除。
cout<<str<<endl; //输出:aghnoyz (是字符集!!!)
关键在于使用了 sort( ) 函数对字符串进行排序,排序后的字符串相同字符都会集中出现,所以unique()就能正确发挥功能了。
6、上面所展示的是把获取的字符集存储在了源字符串变量中,如果遇到要把得到的字符集放置在其他的变量中的情况,就要用到 unique_copy() 函数了。来看一段代码:
string str = "zhaohaoyang";
string dststr; //其他的变量中
dststr.resize(str.size()); //分配空间
sort(str.begin(), str.end()); //先进行排序,
//再进行unique_copy 调用,再调用 erase 函数 删除。
dststr.resize( unique_copy(str.begin(), str.end(), dststr.begin()) - dststr.begin() );
cout<<dststr<<endl; //输出:aghnoyz
dststr 是存储字符集的目标串,str 是源字符串变量。
dststr 在用之前必须要先设置大小,否则到 unique_copy() 的时候会报内存错误,因为是要存储字符串的字符集,所以 dststr 设置和源字符串相同的大小是完全可以的,最后再把剩余的位置 erase 掉就好了。
完整代码:
//求取字符串的字符集
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<numeric>
#include<functional>
using namespace std;
int main(void)
{
string str = "zhaohaoyang";
vector<char> vecch(str.begin(), str.end());
sort(str.begin(), str.end()); //先进行排序,
//再进行unique 调用,再调用 erase 函数 删除:此时,得到的输出字符集是存储在源字符串的位置上的,源字符串已经没了。
//那我现在想要把输出字符集输出在另外一个变量上呢?怎么办?
//方法1:得到的输出字符集是存储在源字符串的位置上的,源字符串已经没了。
str.erase( unique(str.begin(), str.end()), str.end() );
//方法2:输出字符集输出在另外一个变量上,源字符串还存在。
//string strdst;
//strdst.resize(str.size());
//strdst.resize( unique_copy(str.begin(), str.end(), strdst.begin()) - strdst.begin() );
//cout<<strdst.size()<<" "<<strdst<<endl; //输出:aghnoyz (是字符集!!!)
cout<<str.size()<<" "<<str<<endl; //输出:aghnoyz (是字符集!!!)
system("pause");
return 0;
}
7、参考我的博客:
有一个题目:
20170819_去除掉重复元素使其唯一并排序