网站服务器可以更换吗信用门户网站建设观摩
网站服务器可以更换吗,信用门户网站建设观摩,wordpress和iss,wordpress主机分类信息网站0 前言: STL#xff0c;为什么你必须掌握 对于程序员来说#xff0c;数据结构是必修的一门课。从查找到排序#xff0c;从链表到二叉树#xff0c;几乎所有的算法和原理都需要理解#xff0c;理解不了也要死记硬背下来。幸运的是这些理论都已经比较成熟#xff0c;算法也… 0 前言: STL为什么你必须掌握 对于程序员来说数据结构是必修的一门课。从查找到排序从链表到二叉树几乎所有的算法和原理都需要理解理解不了也要死记硬背下来。幸运的是这些理论都已经比较成熟算法也基本固定下来不需要你再去花费心思去考虑其算法原理也不用再去验证其准确性。不过等你开始应用计算机语言来工作的时候你会发现面对不同的需求你需要一次又一次去用代码重复实现这些已经成熟的算法而且会一次又一次陷入一些由于自己疏忽而产生的bug中。这时你想找一种工具已经帮你实现这些功能你想怎么用就怎么用同时不影响性能。你需要的就是STL, 标准模板库 西方有句谚语不要重复发明轮子 STL几乎封装了所有的数据结构中的算法从链表到队列从向量到堆栈对hash到二叉树从搜索到排序从增加到删除......可以说如果你理解了STL你会发现你已不用拘泥于算法本身从而站在巨人的肩膀上去考虑更高级的应用。 排序是最广泛的算法之一本文详细介绍了STL中不同排序算法的用法和区别。 1 STL提供的Sort 算法 C之所以得到这么多人的喜欢是因为它既具有面向对象的概念又保持了C语言高效的特点。STL 排序算法同样需要保持高效。因此对于不同的需求STL提供的不同的函数不同的函数实现的算法又不尽相同。 1.1 所有sort算法介绍
所有的sort算法的参数都需要输入一个范围[begin, end)。这里使用的迭代器(iterator)都需是随机迭代器(RadomAccessIterator), 也就是说可以随机访问的迭代器如itn什么的。partition 和stable_partition 除外 如果你需要自己定义比较函数你可以把你定义好的仿函数(functor)作为参数传入。每种算法都支持传入比较函数。以下是所有STL sort算法函数的名字列表:
函数名功能描述sort对给定区间所有元素进行排序stable_sort对给定区间所有元素进行稳定排序partial_sort对给定区间所有元素部分排序partial_sort_copy对给定区间复制并排序nth_element找出给定区间的某个位置对应的元素is_sorted判断一个区间是否已经排好序partition使得符合某个条件的元素放在前面stable_partition相对稳定的使得符合某个条件的元素放在前面
其中nth_element 是最不易理解的实际上这个函数是用来找出第几个。例如找出包含7个元素的数组中排在中间那个数的值此时我可能不关心前面也不关心后面我只关心排在第四位的元素值是多少。 1.2 sort 中的比较函数
当你需要按照某种特定方式进行排序时你需要给sort指定比较函数否则程序会自动提供给你一个比较函数。 vector int vect;
//...
sort(vect.begin(), vect.end());
//此时相当于调用
sort(vect.begin(), vect.end(), lessint() ); 上述例子中系统自己为sort提供了less仿函数。在STL中还提供了其他仿函数以下是仿函数列表:
名称功能描述equal_to相等not_equal_to不相等less小于greater大于less_equal小于等于greater_equal大于等于
需要注意的是这些函数不是都能适用于你的sort算法如何选择决定于你的应用。另外不能直接写入仿函数的名字而是要写其重载的()函数
lessint()
greaterint()当你的容器中元素时一些标准类型int float char)或者string时你可以直接使用这些函数模板。但如果你时自己定义的类型或者你需要按照其他方式排序你可以有两种方法来达到效果一种是自己写比较函数。另一种是重载类型的操作赋。 #include iostream
#include algorithm
#include functional
#include vector
using namespace std;class myclass {public:myclass(int a, int b):first(a), second(b){}int first;int second;bool operator (const myclass m)const {return first m.first;}
};bool less_second(const myclass m1, const myclass m2) {return m1.second m2.second;
}int main() {vector myclass vect;for(int i 0 ; i 10 ; i ){myclass my(10-i, i*3);vect.push_back(my);}for(int i 0 ; i vect.size(); i ) cout(vect[i].first,vect[i].second)/n;sort(vect.begin(), vect.end());coutafter sorted by first:endl;for(int i 0 ; i vect.size(); i ) cout(vect[i].first,vect[i].second)/n;coutafter sorted by second:endl;sort(vect.begin(), vect.end(), less_second);for(int i 0 ; i vect.size(); i ) cout(vect[i].first,vect[i].second)/n;return 0 ;
} 知道其输出结果是什么了吧
(10,0)
(9,3)
(8,6)
(7,9)
(6,12)
(5,15)
(4,18)
(3,21)
(2,24)
(1,27)
after sorted by first:
(1,27)
(2,24)
(3,21)
(4,18)
(5,15)
(6,12)
(7,9)
(8,6)
(9,3)
(10,0)
after sorted by second:
(10,0)
(9,3)
(8,6)
(7,9)
(6,12)
(5,15)
(4,18)
(3,21)
(2,24)
(1,27)1.3 sort 的稳定性
你发现有sort和stable_sort还有 partition 和stable_partition 感到奇怪吧。其中的区别是带有stable的函数可保证相等元素的原本相对次序在排序后保持不变。或许你会问既然相等你还管他相对位置呢也分不清楚谁是谁了这里需要弄清楚一个问题这里的相等是指你提供的函数表示两个元素相等并不一定是一摸一样的元素。 例如如果你写一个比较函数: bool less_len(const string str1, const string str2)
{return str1.length() str2.length();
} 此时apple 和 winter 就是相等的如果在apple 出现在winter前面用带stable的函数排序后他们的次序一定不变如果你使用的是不带stable的函数排序那么排序完后Winter有可能在apple的前面。 1.4 全排序
全排序即把所给定范围所有的元素按照大小关系顺序排列。用于全排序的函数有 template class RandomAccessIterator
void sort(RandomAccessIterator first, RandomAccessIterator last);template class RandomAccessIterator, class StrictWeakOrdering
void sort(RandomAccessIterator first, RandomAccessIterator last,
StrictWeakOrdering comp);template class RandomAccessIterator
void stable_sort(RandomAccessIterator first, RandomAccessIterator last);template class RandomAccessIterator, class StrictWeakOrdering
void stable_sort(RandomAccessIterator first, RandomAccessIterator last,
StrictWeakOrdering comp); 在第13种形式中sort 和 stable_sort都没有指定比较函数系统会默认使用operator 对区间[first,last)内的所有元素进行排序, 因此如果你使用的类型义军已经重载了operator函数那么你可以省心了。第2, 4种形式你可以随意指定比较函数应用更为灵活一些。来看看实际应用 班上有10个学生我想知道他们的成绩排名。 #include iostream
#include algorithm
#include functional
#include vector
#include string
using namespace std;class student{public:student(const string a, int b):name(a), score(b){}string name;int score;bool operator (const student m)const {return score m.score;}
};int main() {vector student vect;student st1(Tom, 74);vect.push_back(st1);st1.nameJimy;st1.score56;vect.push_back(st1);st1.nameMary;st1.score92;vect.push_back(st1);st1.nameJessy;st1.score85;vect.push_back(st1);st1.nameJone;st1.score56;vect.push_back(st1);st1.nameBush;st1.score52;vect.push_back(st1);st1.nameWinter;st1.score77;vect.push_back(st1);st1.nameAndyer;st1.score63;vect.push_back(st1);st1.nameLily;st1.score76;vect.push_back(st1);st1.nameMaryia;st1.score89;vect.push_back(st1);cout------before sort...endl;for(int i 0 ; i vect.size(); i ) coutvect[i].name:/tvect[i].scoreendl;stable_sort(vect.begin(), vect.end(),lessstudent());cout -----after sort ....endl;for(int i 0 ; i vect.size(); i ) coutvect[i].name:/tvect[i].scoreendl;return 0 ;
} 其输出是
------before sort...
Tom: 74
Jimy: 56
Mary: 92
Jessy: 85
Jone: 56
Bush: 52
Winter: 77
Andyer: 63
Lily: 76
Maryia: 89
-----after sort ....
Bush: 52
Jimy: 56
Jone: 56
Andyer: 63
Tom: 74
Lily: 76
Winter: 77
Jessy: 85
Maryia: 89
Mary: 92sort采用的是成熟的快速排序算法(目前大部分STL版本已经不是采用简单的快速排序而是结合内插排序算法)。
注1
可以保证很好的平均性能、复杂度为n*log(n)由于单纯的快速排序在理论上有最差的情况性能很低其算法复杂度为n*n但目前大部分的STL版本都已经在这方面做了优化因此你可以放心使用。stable_sort采用的是归并排序分派足够内存是其算法复杂度为n*log(n), 否则其复杂度为n*log(n)*log(n)其优点是会保持相等元素之间的相对位置在排序前后保持一致。 1.5 局部排序
局部排序其实是为了减少不必要的操作而提供的排序方式。其函数原型为 template class RandomAccessIterator
void partial_sort(RandomAccessIterator first,
RandomAccessIterator middle,
RandomAccessIterator last);template class RandomAccessIterator, class StrictWeakOrdering
void partial_sort(RandomAccessIterator first,
RandomAccessIterator middle,
RandomAccessIterator last,
StrictWeakOrdering comp);template class InputIterator, class RandomAccessIterator
RandomAccessIterator partial_sort_copy(InputIterator first, InputIterator last,
RandomAccessIterator result_first,
RandomAccessIterator result_last);template class InputIterator, class RandomAccessIterator,
class StrictWeakOrdering
RandomAccessIterator partial_sort_copy(InputIterator first, InputIterator last,
RandomAccessIterator result_first,
RandomAccessIterator result_last, Compare comp); 理解了sort 和stable_sort后再来理解partial_sort 就比较容易了。先看看其用途: 班上有10个学生我想知道分数最低的5名是哪些人。如果没有partial_sort你就需要用sort把所有人排好序然后再取前5个。现在你只需要对分数最低5名排序把上面的程序做如下修改 stable_sort(vect.begin(), vect.end(),lessstudent());
替换为
partial_sort(vect.begin(), vect.begin()5, vect.end(),lessstudent()); 输出结果为
------before sort...
Tom: 74
Jimy: 56
Mary: 92
Jessy: 85
Jone: 56
Bush: 52
Winter: 77
Andyer: 63
Lily: 76
Maryia: 89
-----after sort ....
Bush: 52
Jimy: 56
Jone: 56
Andyer: 63
Tom: 74
Mary: 92
Jessy: 85
Winter: 77
Lily: 76
Maryia: 89这样的好处知道了吗当数据量小的时候可能看不出优势如果是100万学生我想找分数最少的5个人...... partial_sort采用的堆排序heapsort它在任何情况下的复杂度都是n*log(n). 如果你希望用partial_sort来实现全排序你只要让middlelast就可以了。 partial_sort_copy其实是copy和partial_sort的组合。被排序(被复制)的数量是[first, last)和[result_first, result_last)中区间较小的那个。如果[result_first, result_last)区间大于[first, last)区间那么partial_sort相当于copy和sort的组合。 1.6 nth_element 指定元素排序
nth_element一个容易看懂但解释比较麻烦的排序。用例子说会更方便班上有10个学生我想知道分数排在倒数第4名的学生。如果要满足上述需求可以用sort排好序然后取第4位因为是由小到大排), 更聪明的朋友会用partial_sort, 只排前4位然后得到第4位。其实这是你还是浪费因为前两位你根本没有必要排序此时你就需要nth_element: template class RandomAccessIterator
void nth_element(RandomAccessIterator first, RandomAccessIterator nth,
RandomAccessIterator last);template class RandomAccessIterator, class StrictWeakOrdering
void nth_element(RandomAccessIterator first, RandomAccessIterator nth,
RandomAccessIterator last, StrictWeakOrdering comp); 对于上述实例需求你只需要按下面要求修改1.4中的程序 stable_sort(vect.begin(), vect.end(),lessstudent());
替换为
nth_element(vect.begin(), vect.begin()3, vect.end(),lessstudent()); 运行结果为
------before sort...
Tom: 74
Jimy: 56
Mary: 92
Jessy: 85
Jone: 56
Bush: 52
Winter: 77
Andyer: 63
Lily: 76
Maryia: 89
-----after sort ....
Jone: 56
Bush: 52
Jimy: 56
Andyer: 63
Jessy: 85
Mary: 92
Winter: 77
Tom: 74
Lily: 76
Maryia: 89第四个是谁Andyer这个倒霉的家伙。为什么是begin()3而不是4? 我开始写这篇文章的时候也没有在意后来在
ilovevc的提醒下发现了这个问题。begin()是第一个begin()1是第二个... begin()3当然就是第四个了。 1.7 partition 和stable_partition
好像这两个函数并不是用来排序的分类算法会更加贴切一些。partition就是把一个区间中的元素按照某个条件分成两类。其函数原型为 template class ForwardIterator, class Predicate
ForwardIterator partition(ForwardIterator first,
ForwardIterator last, Predicate pred)
template class ForwardIterator, class Predicate
ForwardIterator stable_partition(ForwardIterator first, ForwardIterator last,
Predicate pred); 看看应用吧班上10个学生计算所有没有及格低于60分的学生。你只需要按照下面格式替换1.4中的程序 stable_sort(vect.begin(), vect.end(),lessstudent());
替换为
student exam(pass, 60);
stable_partition(vect.begin(), vect.end(), bind2nd(lessstudent(), exam)); 其输出结果为
------before sort...
Tom: 74
Jimy: 56
Mary: 92
Jessy: 85
Jone: 56
Bush: 52
Winter: 77
Andyer: 63
Lily: 76
Maryia: 89
-----after sort ....
Jimy: 56
Jone: 56
Bush: 52
Tom: 74
Mary: 92
Jessy: 85
Winter: 77
Andyer: 63
Lily: 76
Maryia: 89看见了吗JimyJone, Bush(难怪说美国总统比较笨 )都没有及格。而且使用的是stable_partition, 元素之间的相对次序是没有变. 2 Sort 和容器 STL中标准容器主要vector, list, deque, string, set, multiset, map, multimay 其中set, multiset, map, multimap都是以树结构的方式存储其元素详细内容请参看
学习STL map, STL set之数据结构基础
. 因此在这些容器中元素一直是有序的。 这些容器的迭代器类型并不是随机型迭代器因此上述的那些排序函数对于这些容器是不可用的。上述sort函数对于下列容器是可用的
vectorstringdeque
如果你自己定义的容器也支持随机型迭代器那么使用排序算法是没有任何问题的。 对于list容器list自带一个sort成员函数list::sort(). 它和算法函数中的sort差不多但是list::sort是基于指针的方式排序也就是说所有的数据移动和比较都是此用指针的方式实现因此排序后的迭代器一直保持有效vector中sort后的迭代器会失效). 3 选择合适的排序函数 为什么要选择合适的排序函数可能你并不关心效率(这里的效率指的是程序运行时间), 或者说你的数据量很小 因此你觉得随便用哪个函数都无关紧要。 其实不然即使你不关心效率如果你选择合适的排序函数你会让你的代码更容易让人明白你会让你的代码更有扩充性逐渐养成一个良好的习惯很重要吧 。 如果你以前有用过C语言中的qsort, 想知道qsort和他们的比较那我告诉你qsort和sort是一样的因为他们采用的都是快速排序。从效率上看以下几种sort算法的是一个排序效率由高到低耗时由小变大
partionstable_partitionnth_elementpartial_sortsortstable_sort
记得以前翻译过Effective STL的文章其中对
如何选择排序函数
总结的很好
若需对vector, string, deque, 或 array容器进行全排序你可选择sort或stable_sort若只需对vector, string, deque, 或 array容器中取得top n的元素部分排序partial_sort是首选.若对于vector, string, deque, 或array容器你需要找到第n个位置的元素或者你需要得到top n且不关系top n中的内部顺序nth_element是最理想的若你需要从标准序列容器或者array中把满足某个条件或者不满足某个条件的元素分开你最好使用partition或stable_partition若使用的list容器你可以直接使用partition和stable_partition算法你可以使用list::sort代替sort和stable_sort排序。若你需要得到partial_sort或nth_element的排序效果你必须间接使用。正如上面介绍的有几种方式可以选择。
总之记住一句话
如果你想节约时间不要走弯路, 也不要走多余的路!4 小结 讨论技术就像个无底洞经常容易由一点可以引申另外无数个技术点。因此需要从全局的角度来观察问题就像观察STL中的sort算法一样。其实在STL还有make_heap, sort_heap等排序算法。本文章没有提到。本文以实例的方式解释了STL中排序算法的特性并总结了在实际情况下应如何选择合适的算法。 5 参考文档
条款31如何选择排序函数The Standard Librarian: Sorting in the Standard LibraryEffective STL中文版Standard Template Library Programmers Guide注1本文此处最初有错误由
owen nirvana
提醒表示感谢。 论坛讨论 :讨论详细解说 STL 排序(Sort)
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/89027.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!