您的位置:首页 > 编程语言 > C语言/C++

C++ 排序函数 sort(),qsort()的用法

2017-05-25 09:02 645 查看
C库函数qsort,C++库函数sort。其中qsort相对较慢,sort实现非常高效qsort:功 能: 使用快速排序例程进行排序头文件:#include<qsort>用 法: void qsort(void *base,int nelem,int width,int (*fcmp)(const void *,const void *));参数: 1 待排序数组首地址2 数组中待排序元素数量3 各元素的占用空间大小4 指向函数的指针,用于确定排序的顺序C++  qsort函数头文件:#include <algorithm>默认的sort函数是按升序排。所以自己总结了一下,首先看sort函数见下表:   
函数名功能描述
sort对给定区间所有元素进行排序
stable_sort对给定区间所有元素进行稳定排序
partial_sort对给定区间所有元素部分排序
partial_sort_copy对给定区间复制并排序
nth_element找出给定区间的某个位置对应的元素
is_sorted判断一个区间是否已经排好序
partition使得符合某个条件的元素放在前面
stable_partition相对稳定的使得符合某个条件的元素放在前面
 要使用此函数只需用#include <algorithm> 即可使用sort,语法描述为:sort(begin,end),表示一个范围,例如:int _tmain(int argc, _TCHAR* argv[]){ int a[20]={2,4,1,23,5,76,0,43,24,65},i; for(i=0;i<20;i++)  cout<<a[i]<<endl; sort(a,a+20); for(i=0;i<20;i++) cout<<a[i]<<endl; return 0;}输出结果将是把数组a按升序排序,说到这里可能就有人会问怎么样用它降序排列呢?这就是下一个讨论的内容. 一种是自己编写一个比较函数来实现,接着调用三个参数的sort:sort(begin,end,compare)就成了。对于list容器,这个方法也适用,把compare作为sort的参数就可以了,即:sort(compare).
sort(数组名,数组末地址,compare)    //若不写compare则默认升序排列
关于参数compare,compare带两个同类型的参数,如果第一个参数排在第二个参数前面4000,返回true,否则返回false1)自己编写compare函数:bool compare(int a,int b){      return a<b;   //升序排列,如果改为return a>b,则为降序}int _tmain(int argc, _TCHAR* argv[]){     int a[20]={2,4,1,23,5,76,0,43,24,65},i;     for(i=0;i<20;i++)       cout<<a[i]<<endl;     sort(a,a+20,compare);     for(i=0;i<20;i++)       cout<<a[i]<<endl;     return 0;}2)更进一步,让这种操作更加能适应变化。也就是说,能给比较函数一个参数,用来指示是按升序还是按降序排,这回轮到函数对象出场了。为了描述方便,我先定义一个枚举类型EnumComp用来表示升序和降序。很简单:enum Enumcomp{ASC,DESC};然后开始用一个类来描述这个函数对象。它会根据它的参数来决定是采用“<”还是“>”。class compare{      private:            Enumcomp comp;      public:            compare(Enumcomp c):comp(c) {};      bool operator () (int num1,int num2)          {            switch(comp)              {                 case ASC:                        return num1<num2;                 case DESC:                        return num1>num2;              }          }};接下来使用 sort(begin,end,compare(ASC)实现升序,sort(begin,end,compare(DESC)实现降序。主函数为:int main(){     int a[20]={2,4,1,23,5,76,0,43,24,65},i;     for(i=0;i<20;i++)         cout<<a[i]<<endl;     sort(a,a+20,compare(DESC));     for(i=0;i<20;i++)         cout<<a[i]<<endl;     return 0;}3)其实对于这么简单的任务(类型支持“<”、“>”等比较运算符),完全没必要自己写一个类出来。标准库里已经有现成的了,就在functional里,include进来就行了。functional提供了一堆基于模板的比较函数对象。它们是(看名字就知道意思了):equal_to<Type>、not_equal_to<Type>、greater<Type>、greater_equal<Type>、less<Type>、less_equal<Type>。对于这个问题来说,greater和less就足够了,直接拿过来用:升序:sort(begin,end,less<data-type>());降序:sort(begin,end,greater<data-type>()).int _tmain(int argc, _TCHAR* argv[]){      int a[20]={2,4,1,23,5,76,0,43,24,65},i;      for(i=0;i<20;i++)          cout<<a[i]<<endl;      sort(a,a+20,greater<int>());      for(i=0;i<20;i++)          cout<<a[i]<<endl;      return 0;}4)既然有迭代器,如果是string 就可以使用反向迭代器来完成逆序排列,程序如下:int main(){     string str("cvicses");     string s(str.rbegin(),str.rend());     cout << s <<endl;     return 0;}STL容器的排序,支持随机访问的容器vector,deque,string没有sort成员,可调用std::sort排序;list排序调用自带的list::sort。下面是std::sort函数,有两个版本:[cpp] viewplaincopytemplate <class RandomAccessIterator>  void sort ( RandomAccessIterator first, RandomAccessIterator last );    template <class RandomAccessIterator, class Compare>  void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );  sort函数有以下特征:1. 要求输入一个范围[first, last)2. 随机迭代器,能用此算法的容器是支持随机访问的容器:vector, deque, string。3.第一个版本使用operator<进行比较,默认升序排序,第二个版本使用comp做比较.关于参数comp,comp带两个同类型的参数,如果第一个参数排在第二个参数前面,返回true,否则返回false它可以是函数指针,也可以是函数对象。函数指针好理解,何谓函数对象?函数对象(Function Object),是重载了operator()函数的类(或结构体)实例化出来的对象,使用起来像函数,又叫仿函数。STL本身提供了几个比较函数,下面这些都是仿函数:less(小于)greater(大于)equal_to(等于)not_equal_to(不相等)less_equal(小于等于)greater_equal(大于等于)当容器元素为内建类型时可以使用,注意使用的格式,要加模版参数(由于是模板类)和后面的(),如下:[cpp] viewplaincopysort(vec.begin(), vec.end(), less<int>());  对于复合类型,实现排序方式有3种方法:1)重载operator<操作符2)写全局的比较函数3)写仿函数,重载operator()形式为:booloperator()(const 类名& 参数){…}下面看看这3种方法的实现:[cpp] viewplaincopy// 排序元素,比较的对象  struct Person  {    Person(int id, const string& name, int age): id_(id), name_(name), age_(age)    {}        int id_;    string name_;    int age_;  };  [cpp] viewplaincopy// 方式1:重载operator<用于排序时的比较(写在函数体内)  bool operator< (const Person& rt)  {    return this->id_ < rt.id_;  }    // 排序函数写法,默认调用operator<  sort(members.begin(), members.end());  [cpp] viewplaincopy// 方式2:写比较函数  bool CompAge(const Person& pl, const Person& pr)  {    return pl.age_ < pr.age_;  }    // 排序时传入比较函数指针  sort(members.begin(), members.end(), CompAge);  [cpp] viewplaincopy// 方式3:仿函数  struct CompName  {    bool operator()(const Person& pl, const Person& pr)    {      return pl.name_ < pr.name_;    }  };    // 排序时传入函数对象  sort(members.begin(), members.end(), CompName());  用函数对象代替函数指针的优点:1. 函数对象可以存储中间结果在数据成员中,而函数想要存中间结果须要设全局变量或静态变量,这个是我们不想要的。2. 在函数对象中编译器可以实现内联调用,从而提升性能。下面看一个函数对象的扩展应用[cpp] viewplaincopy// 利用函数对象实现升降排序  struct CompNameEx{    CompNameEx(bool asce) : asce_(asce)    {}    bool operator()(const Person& pl, const Person& pr)    {      return asce_ ? pl.name_ < pr.name_ : pr.name_ < pl.name_;<span style="white-space:pre">   </span>// 《Eff STL》条款21: 永远让比较函数对相等的值返回false    }  private:    bool asce_;  };  // 使用仿函数排序(升降序)  sort(members.begin(), members.end(), CompNameEx(false));  注意:如果是指针的容器,比较函数的参数也应是指针。

C++sort()函数的用法

近来看了c++标准库这本书,学到了很多,就把这其中的一点C++sort()函数的用法写下来和大家分享吧!

(一)为什么要用c++标准库里的排序函数Sort()函数是c++一种排序方法之一,学会了这种方法也打消我学习c++以来使用的冒泡排序和选择排序所带来的执行效率不高的问题!因为它使用的排序方法是类似于快排的方法,时间复杂度为n*log2(n),执行效率较高!(二)c++标准库里的排序函数的使用方法I)Sort函数包含在头文件为#include<algorithm>的c++标准库中,调用标准库里的排序方法可以不必知道其内部是如何实现的,只要出现我们想要的结果即可!II)Sort函数有三个参数:(1)第一个是要排序的数组的起始地址。(2)第二个是结束的地址(最后一位要排序的地址)(3)第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。Sort函数使用模板:Sort(start,end,排序方法)下面就具体使用sort()函数结合对数组里的十个数进行排序做一个说明!例一:sort函数没有第三个参数,实现的是从小到大#include<iostream>#include<algorithm>using namespace std;int main(){ int a[10]={9,6,3,8,5,2,7,4,1,0}; for(int i=0;i<10;i++) cout<<a[i]<<endl;sort(a,a+10); for(int i=0;i<10;i++) cout<<a[i]<<endl; return 0;}例二通过上面的例子,会产生疑问:要实现从大到小的排序肿么办? 这就如前文所说需要在sort()函数里的第三个参数里做文章了,告诉程序我要从大到小排序!需要加入一个比较函数 complare(),此函数的实现过程是这样的bool complare(int a,int b){ return a>b;}这就是告诉程序要实现从大到小的排序的方法!#include<iostream>#include<algorithm>using namespace std;bool complare(int a,int b){ return a>b;}int main(){ int a[10]={9,6,3,8,5,2,7,4,1,0}; for(int i=0;i<10;i++) cout<<a[i]<<endl; sort(a,a+10,complare);//在这里就不需要对complare函数传入参数了,//这是规则 for(int i=0;i<10;i++) cout<<a[i]<<endl; return 0;}例三:通过上面例一、二的方法虽然实现了从大到小和从大到小的排序,这样做还是有点麻烦,因为还需要自己编写告诉程序执行何种排序的原则的函数,c++标准库强大的功能完全可以解决这种麻烦。Sortt函数的第三个参数可以用这样的语句告诉程序你所采用的排序原则less<数据类型>()//从小到大排序greater<数据类型>()//从大到小排序结合本例子,这样的就可以完成你想要的任何一种排序原则了#include<iostream>#include<algorithm>using namespace std;int main(){ int a[10]={9,6,3,8,5,2,7,4,1,0}; for(int i=0;i<10;i++) cout<<a[i]<<endl;sort(a,a+10,less<int>()); for(int i=0;i<10;i++) cout<<a[i]<<endl; return 0;}#include<iostream>#include<algorithm>using namespace std;int main(){ int a[10]={9,6,3,8,5,2,7,4,1,0}; for(int i=0;i<10;i++) cout<<a[i]<<endl; sort(a,a+10,greater<int>()); for(int i=0;i<10;i++) cout<<a[i]<<endl; return 0;}例四:利用sort函数还可以实现对字符的排序,排序方法大同小异,下面就把程序范例展示一下#include<iostream>#include<algorithm>using namespace std;int main(){ char a[11]="asdfghjklk"; for(int i=0;i<10;i++) cout<<a[i]<<endl; sort(a,a+10,greater<char>()); for(int i=0;i<10;i++) cout<<a[i]<<endl; return 0;}  qsort():原型:_CRTIMP void __cdecl qsort (void*, size_t, size_t,int (*)(const void*, const void*));解释:    qsort ( 数组名 ,元素个数,元素占用的空间(sizeof),比较函数) 比较函数是一个自己写的函数  遵循 int com(const void *a,const void *b) 的格式。当a b关系为 >  <  = 时,分别返回正值 负值 零 (或者相反)。使用a b 时要强制转换类型,从void * 转换回应有的类型后,进行操作。 数组下标从零开始,个数为N, 下标0-(n-1)。排序的顺序是从大到小还是从小到大取决于compare函数
int compare(const void*a,const void*b){return *(*int)a-*(int*)b;}  //升序排序的写法,
示例:qsort(a,10,sizeof(int),compare)    //假设已定义了整型数组a[10]
如果是:return *(*int)b-*(int*)a   就是降序,不论是什么类型的数组,该函数的形式都是这样的
qsort 函数执行期间,需要比较两个元素哪个应在前面时,就以两个元素的地址作为参数,调用 Compare 函数。如果返回值小于0,则qsort 就得知第一个元素应该在前,如果返回值大于0,则第一个元素应该在后。如果返回值等于0,则哪个在前都行。
qsort 函数的用法规定,“比较函数”的原型应是:int 函数名(const void * elem1, const void * elem2);该函数的两个参数,elem1 和elem2,指向待比较的两个元素。也就是说, * elem1 和* elem2 就是待比较的两个元素。该函数必须具有以下行为:  1) 如果 * elem1 应该排在 * elem2 前面,则函数返回值是负整数(任何负整数都行)。  2) 如果 * elem1 和* elem2 哪个排在前面都行,那么函数返回0  3) 如果 * elem1 应该排在 * elem2 后面,则函数返回值是正整数(任何正整数都行)。一定注意qsort与sort函数中自定义的比较函数compare中哪个元素应该排在前面的要求是不同的。实例:int compare(const void *a,const void *b){     return *(int*)b-*(int*)a;   }int main(){     int a[20]={2,4,1,23,5,76,0,43,24,65},i;     for(i=0;i<20;i++)        cout<<a[i]<<endl;     qsort((void *)a,20,sizeof(int),compare);     for(i=0;i<20;i++)        cout<<a[i]<<endl;     return 0;}相关:1)why你必须给予元素个数?因为阵列不知道它自己有多少个元素2)why你必须给予大小?因为 qsort 不知道它要排序的单位.3)why你必须写那个丑陋的、用来比较俩数值的函式?因为 qsort 需要一个指标指向某个函式,因为它不知道它所要排序的元素型别.4)why qsort 所使用的比较函式接受的是 const void* 引数而不是 char* 引数?因为 qsort 可以对非字串的数值排序. C/C++中有一个快速排序的标准库函数 qsort ,在stdlib.h 中声明,其原型为:void qsort(void *base, int nelem, unsigned int width, int ( * pfCompare)( const void *, const void *));  使用该函数,可以对任何类型的一维数组排序。该函数参数中,base 是待排序数组的起始地址,nelem 是待排序数组的元素个数,width 是待排序数组的每个元素的大小(以字节为单位),最后一个参数 pfCompare 是一个函数指针,它指向一个“比较函数”。排序就是一个不断比较并交换位置的过程。qsort 如何在连元素的类型是什么都不知道的情况下,比较两个元素并判断哪个应该在前呢?答案是,qsort 函数在执行期间,会通过pfCompare指针调用一个 “比较函数”,用以判断两个元素哪个更应该排在前面。这个“比较函数”不是C/C++的库函数,而是由使用qsort的程序员编写的。在调用qsort 时, 将“比较函数”的名字作为实参传递给pfCompare。程序员当然清楚该按什么规则决定哪个元素应该在前,哪个元素应该在后,这个规则就体现在“比较函数”中。qsort 函数的用法规定,“比较函数”的原型应是:int 函数名(const void * elem1, const void * elem2);该函数的两个参数,elem1 和elem2,指向待比较的两个元素。也就是说, * elem1 和* elem2 就是待比较的两个元素。该函数必须具有以下行为:  1) 如果 * elem1 应该排在 * elem2 前面,则函数返回值是负整数(任何负整数都行)。  2) 如果 * elem1 和* elem2 哪个排在前面都行,那么函数返回0  3) 如果 * elem1 应该排在 * elem2 后面,则函数返回值是正整数(任何正整数都行)。例如:#include <iostream>#include <stdio.h>#include <stdlib.h>using namespace std;int compare(const void *a, const void *b){    int *pa = (int*)a;    int *pb = (int*)b;    return (*pa )- (*pb);  //从小到大排序}void main(){    int a[10] = {5, 6, 4, 3, 7, 0 ,8, 9, 2, 1};    qsort(a, 10, sizeof(int), compare);    for (int i = 0; i < 10; i++)        cout << a[i] << " " << endl;} 再如:下面的程序,功能是调用qsort 库函数,将一个unsigned int 数组按照个位数从小到大进行排序。比如 8,23,15 三个数,按个位数从小到大排序,就应该是 23,15,8:#include <stdio.h>#include <stdlib.h>int MyCompare( const void * elem1, const void * elem2{  unsigned int * p1, * p2;  p1 = (unsigned int *) elem1;  //语句6  p2 = (unsigned int *) elem2;  //语句7  return (* p1 % 10) - (* p2 % 10 );  //语句8}#define NUM 5int main(){  unsigned int an[NUM] = { 8,123,11,10,4 };  qsort( an, NUM, sizeof(unsigned int), MyCompare);  for( int i = 0;i < NUM; i ++ )    printf("%d ", an[i]);  return 0;} 上面程序的输出结果是:10 11 123 4 8qsort 函数执行期间,需要比较两个元素哪个应在前面时,就以两个元素的地址作为参数,调用 MyCompare 函数。如果返回值小于0,则qsort 就得知第一个元素应该在前,如果返回值大于0,则第一个元素应该在后。如果返回值等于0,则哪个在前都行。对语句6 解释如下:由于elem1 是 const void * 类型的,是void 指针,那么表达式“*elem1”是没有意义的。elem1 应指向待比较的元素,即一个unsigned int 类型的变量,所以要经过强制类型转换,将elem1 里存放的地址赋值给 p1,这样,* p1 就是待比较的第一个元素了。语句7 同理。语句8 体现了排序的规则。如果 *p1 的个位数小于 *p2 的个位数,那么就返回负值。其他两种情况不再赘述。 
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言 c++