C中的qsort函数和C++中的sort函数的理解与使用

本文深入解析C中的qsort函数和C++中的sort函数,包括函数原型、参数解释、常见用法及自定义比较函数的多种实现方式,对比两者的性能与适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 qsort()函数

原型:

_CRTIMP void __cdecl qsort (void*, size_t, size_t,int (*)(const void*, const void*));

参数解释:
1、待排序数组首地址;2、数组中待排序元素数量;3、各元素的占用空间的大小;4、指向函数的指针,用于确定排序的顺序。

说明:qsort函数是ANSI C标准中提供的,其声明在stdlib.h文件中,是根据二分法写的,时间复杂度为O(n*logn)。qsort要求提供比较函数用来确定排序的顺序(升序、降序),比较函数使得qsort通用性更好,可以对数组、字符串、结构体数进行排序。如int cmp(const void *a, const void *b)中有两个元素作为参数(参数的格式不能变的。)返回一个int值,如果比较函数返回大于0,qsort就认为a > b,返回小于0,qsort就认为a < b。

1.1 qsort中几种常见的cmp函数

1.1、对int类型数组排序

int num[100];
int cmp(const void *a, const void *b)
{
    return *(int *)a - *(int *)b;
}
qsort(num, 100, sizeof(int), cmp);

1.2、对char类型数组排序

char num[100];
int cmp(const void *a, const void *b)
{
    return *(char *)a - *(char *)b;
}

qsort(num, 100, sizeof(char), cmp);

1.3、对double类型数组排序

double num[100];
int cmp(const void *a, const void *b)
{
    return *(double *)a > *(double *)b;
}

qsort(num, 100, sizeof(double), cmp);

1.4、对结构体数组一级排序

struct In
{
    double data;
    int other;
}s[100]
//按照data的值从小到大将结构体排序,关于结构体内的排序关键数据data的类型可以很多种,参考上面的例子写 
int cmp( const void *a ,const void *b)
{
    return (*(In *)a)->data > (*(In *)b)->data ? 1 : -1;
}

qsort(s,100,sizeof(In),cmp); 

1.5、对结构体数组二级排序

struct In
{
    int x;
    int y;
}s[100];
//按照x从小到大排序,当x相等时按照y从大到小排序 
int cmp( const void *a , const void *b )
{
    struct In *c = (In *)a;
    struct In *d = (In *)b;
    if(c->x != d->x) 
        return c->x - d->x;
    else
        return d->y - c->y;
}

qsort(s,100,sizeof(In),cmp);       

1.6、对字符串进行排序

struct In

{
    int data;
    char str[100];
}s[100];
//按照结构体中字符串str的字典顺序排序 
int cmp ( const void *a , const void *b )
{
    return strcmp( (*(In *)a)->str , (*(In *)b)->str );
}
qsort(s,100,sizeof(In),cmp); 

1.7、计算几何中求凸包的cmp


int cmp(const void *a,const void *b) //重点cmp函数,把除了1点外的所有点,旋转角度排序 
{
    struct point *c=(point *)a;
    struct point *d=(point *)b;
    if( calc(*c,*d,p[1]) < 0) 
    return 1;
    else if( !calc(*c,*d,p[1]) && dis(c->x,c->y,p[1].x,p[1].y) < dis(d->x,d->y,p[1].x,p[1].y)) //如果在一条直线上,则把远的放在前面 
      return 1;
    else 
    return -1;
}

1.2 拓展知识点

  1. 为啥子使用qsort函数要指定排序元素的大小?
    ans:这是个脑残的问题,给个脑残的答案吧。因为qsort需要根据元素的大小来进行排序。
  2. 所使用的比较函式接受的是 const void* 类型?
    ans:因为考虑到qsort的通用性,这样可以对数组,结构体数组等类型进行排序了。

2 sort()函数

函数名功能描述
sort对给定区间所有元素进行排序
stable_sort对给定区间所有元素进行稳定排序
partial_sort对给定区间所有元素部分排序
partial_sort_copy对给定区间复制并排序
nth_element找出给定区间的某个位置对应的元素
is_sorted判断一个区间是否已经排好序
partition使得符合某个条件的元素放在前面
stable_partition相对稳定的使得符合某个条件的元素放在前面

要使用上述函数必须加上头文件algorithm。

2.1 sort(begin,end)

小例子

#include<algorithm>

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函数降序排序,ok!就像qsort中一样,我们需要自定义一个比较函数cmp(返回值为bool类型)。

2.2 重载的sort函数-带比较函数的sort(begin,end,cmp)

自定义比较函数的方法

2.2.1 比较函数

下面的比较函数可以实现降序排序:

bool cmp(int a,int b)
{
    return a>b;      
}

2.2.2、比较类或者结构体
使用枚举类型enum来定义升序或者降序排序。

//ASC升序,DESC降序
enum Cmp{ASC,DESC};

定义一个比较类,来描述排序的顺序。

class compare
{
      private:
            Cmp comp;
      public:
            compare(Cmp c):comp(c) {};
      bool operator () (int num1,int num2) 
         {
            switch(comp)
              {
                 case ASC:
                        return num1<num2;
                 case DESC:
                        return num1>num2;
              }
          }
};

测试一下:

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;
}

了解一下即可,因为比较麻烦,根据实际情况使用。
使用leetcode一道题作为立即说明自定义比较函数的使用方式:
题目:56. 合并区间

给出一个区间的集合,请合并所有重叠的区间。
示例 1:
输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入: [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。

class Solution {
private:
	//实现一个比较函数
	bool static cmp_range(const vector<int>& l, vector<int>& r) { //在类中此函数必须是静态的
		return l[0] < r[0];
	}
	//实现一个函数对象
	struct CmpRange {
		bool operator()(const vector<int>& l, vector<int>& r) {
			return l[0] < r[0];
		}
	};
public:
	vector<vector<int>> merge(vector<vector<int>>& intervals) {

		vector<vector<int>> vv;
		if (intervals.size() == 0)
			return vv;
		//首先根据区间的起点进行排序,然后再从左到右进行合并    
		//sort(intervals.begin(), intervals.end(), CmpRange()); //可以这样写
        sort(intervals.begin(), intervals.end(), cmp_range); //也可以这样写
		//print_vv(intervals);

		//vv.push_back(intervals[0]);
		vector<int> v;
		int len = intervals.size();
		for (int i = 0; i < len;) {
			v = intervals[i];
			i++;
			while (i < len && intervals[i][0] >= v[0] && intervals[i][0] <= v[1]) {
				v[1] = max(v[1], intervals[i][1]);
				i++;
			}
			//cout << v[0] << " " << v[1] << endl;
			vv.push_back(v);
		}
		return vv;
	}
};

2.2.3、使用functional头文件中的比较对象。
functional提供了一堆基于模板的比较函数对象。equal_to、not_equal_to、greater、greater_equal、less、less_equal。对于这些比较对象,我们可以望文生义就知道它们的意思了。
for example:

sort(begin,end,less<data-type>();//升序
sort(begin,end,greater<data-type>();//降序

接着上面的例子,使用一下比较对象

int _tmain(int argc, _TCHAR* argv[])
{
      int a[10]={2,4,1,23,5,76,0,43,24},i;
      for(i=0;i<20;i++)
          cout<<a[i]<<endl;
      sort(a,a+10,greater<int>());
      for(i=0;i<10;i++)
          cout<<a[i]<<endl;
      return 0;
}

这里可以看到是sort(a,a+10),但是数组a一共只有9个元素,为什么是a+10而不是a+9呢?因为sort方法实际上最后一位地址对应的数是不取的.

2.3 对vector使用sort函数

vector,set,map这些容器的end()取出来的值实际上并不是最后一个值,而end的前一个才是最后一个值!需要用prev(xxx.end()),才能取出容器中最后一个元素。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
    vector<int> a;
    int n = 5;
    while (n--){
        int score;
        cin >> score;
        a.push_back(score);
    }
    //cout <<" a.end()"<< *a.end() << endl;       执行这句话会报错!
    cout << " prev(a.end)" << *prev(a.end()) << endl;
    sort(a.begin(), a.end());
    for (vector<int>::iterator it = a.begin(); it != a.end(); it++){
        cout << *it << endl;
    }
    return 0;
}

2.4 sort的三种比较函数写法

2.4.1 方法1:声明外部比较函数

bool Less(const Student& s1, const Student& s2)
{
    return s1.name < s2.name; //从小到大排序
}
std::sort(sutVector.begin(), stuVector.end(), Less);

**注意:**比较函数必须写在类外部(全局区域)或声明为静态函数.当comp作为类的成员函数时,默认拥有一个this指针,这样和sort函数所需要使用的排序函数类型不一样。否则,会出现错误。

2.4.2 方法2:重载类的比较运算符

bool operator<(const Student& s1, const Student& s2)
{
    return s1.name < s2.name; //从小到大排序
}
std::sort(sutVector.begin(), stuVector.end());

2.4.3 方法3:声明比较类

struct Less
{
    bool operator()(const Student& s1, const Student& s2)
    {
        return s1.name < s2.name; //从小到大排序
    }
};
std::sort(sutVector.begin(), stuVector.end(), Less());

3 qsort函数和sort函数的PK。

3.1 cmp函数不同

返回值类型不同,qsort函数的cmp返回值类型为int,sort函数的cmp返回值为bool。
参数不同,sort函数的cmp可以直接是参与比较的引用类型,而qsort是严格的空指针类型。
比较表达式不同,qsort中的cmp使用的是“-”号,而sort中的cmp使用的是“>”。

3.2 性能的区别

sort函数是c++中标准模板库的的函数,在qsort()上已经进行了优化,根据情况的不同可以采用不同的算法,所以较快。在同样的元素较多和同样的比较条件下,sort()的执行速度都比qsort()要快。另外,sort()是类属函数,可以用于比较任何容器,任何元素,任何条件。

原文链接:

  1. C中的qsort函数和C++中的sort函数的理解与使用
  2. 关于C++中vector和set使用sort方法进行排序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值