这个题目有点儿无聊,跟茴香豆的“茴”字有几种写法一样无聊,又是一个无聊的老掉牙的话题——排序,问题依然是无聊至极——把输入的单词按顺序(我可没说是什么顺序)排列。当作是一个总结吧。
按词典排好说,如果你用vector<string> words存储单词,只需用algorithm里的sort即可:sort(words.begin(),words.end())。这玩意儿我闭着眼也能敲出来。但假如你用list的话……编译器发脾气了吧?(发脾气是好的,要是没有任何抱怨,趁早儿扔了吧)。list容器不支持随机访问,标准库的sort没法用到它上面。幸好list自己带了一个sort,所以要用words.sort()。
如果要按和词典相反的顺序排呢?对sort而言,默认是采用“<”来比较的,如果让它采用“大于”不就行了吗?标准库当然为此“预留了接口”。你可以先写一个比较函数,如compare,记着用大于号“>”比较:
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
接着调用三个参数的sort版本:sort(words.begin(),words.end(),compare)就成了。对于list容器,这个方法也适用,把compare作为sort的参数就可以了,即:words.sort(compare)。
更进一步,我现在要让这种操作更加能适应变化。也就是说,我希望能给比较函数一个参数,用来指示是按升序还是按降序排。这回轮到函数对象出场了。
为了描述方便,我先定义一个枚举类型EnumComp用来表示升序和降序。很简单:
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
然后开始用一个类来描述这个函数对象。它会根据它的参数来决定是采用“<”还是“>”。嗯……我想应该是这个样子的:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
好了,想按升序排,那就sort(words.begin(),words.end().Compare(ASC));想按降序排,就sort(words.begin(),words.end(),Compare(DESC))。
其实对于这么简单的任务(类型支持“<”、“>”等比较运算符),完全没必要自己写一个类出来。标准库里已经有现成的了,就在functional里,把它include进来就行了。functional提供了一堆基于模板的比较函数对象。它们是(看名字就知道意思了):equal_to<Type>、not_equal_to<Type>、greater<Type>、greater_equal<Type>、less<Type>、less_equal<Type>。对于这个问题来说,greater和less就足够了,直接拿过来用:
- 升序:sort(words.begin(),words.end(),less<string>());
- 降序:sort(words.begin(),words.end(),greater<string>()).
上面的几种方法都还算是“正大光明”,那么偏方是什么?看看sort的参数,前两个是迭代器……嗯,记不记得有个“反向迭代器”的玩意儿?没错,默认的sort会用小于号比较,如果换成反向迭代器,不就“骗”过sort了吗?sort(words.rbegin(),words.rend())。
再来考虑一个更难一点儿的问题:按长度递增的顺序排序,长度相同的按字典顺序排。这回如果简单地用两次sort就不行了,第二次的排序很可能会把前一次的成果完全毁掉。根本原因是大多数的sort都是采用“快速排序”算法实现的,而快速排序是一种不稳定排序,也就是说,如果两个元素A和B的值相同,排序前A在B的前面,那么经过快速排序后,并不能保证A仍然在B的前面。现在需要的是一种“稳定排序”的算法,它可以保证在排序后相同值的元素的相对位置不变。
稍微想一下可知,应该先按字典顺序排,再用稳定排序的方法按长度排。标准库提供了一个stable_sort,用来实现稳定排序。先来定义一个字符串长度的比较函数:
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
接着两行代码就完成了任务:
stable_sort(words.begin(),words.end(),length_comp);