C++中sort()函数使用介绍

sort()简介

为什么选择使用sort()

在刷题的时候我们经常会碰到排序的问题,如果我们不使用一些排序的方法那我们只能手撕排序,这样就会浪费一些时间。而且我们还需要根据需要去选择相关的排序方法:冒泡排序、快速排序、插入排序、希尔排序、归并排序、选择排序、堆排序、基数排序、桶排序。在选择的过程中也需要我们花费一些时间,所以在明白这些经典排序的情况下再一遍一遍的手写就有点浪费时间啦!

如果我们使用sort()方法就可以只需要一条语句就可以实现排序,这样就极大的节省了我们在刷题中所花费的时间。当然如果对这些经典的排序方法不熟悉的话还是建议大家去了解一下这些方法,比较一下这些方法的优劣以及使用的情景。

sort()函数的实现原理

也许你会疑问,我使用sort方法对数据进行排序就一定合适吗?sort()可以根据我的需要对数据进行排序吗?其实sort()函数还是一个比较灵活的函数。很多解释是:sort()函数是类似于快速排序的方法,时间复杂度为n*log2(n),执行效率较高。

其实STL中的sort()并非只是普通的快速排序除了对普通的快速排序进行优化,它还结合了插入排序和堆排序。根据不同的数量级别以及不同情况,能自动选用合适的排序方法。当数据量较大时采用快速排序,分段递归。一旦分段后的数据量小于某个阀值,为避免递归调用带来过大的额外负荷,便会改用插入排序。而如果递归层次过深,有出现最坏情况的倾向,还会改用堆排序。所以说sort()是一个比较灵活的函数,它也会根据我们数据的需要进行排序,所以我们就不用担心以上的问题了。对于大部分的排序需求,sort()都是可以满足的。

sort()的使用方法

头文件

在C++中使用sort()函数需要使用#include头文件。algorithm意为"算法",是C++的标准模版库(STL)中最重要的头文件之一,提供了大量基于迭代器的非成员模版函数。该头文件的详细使用方法以及包含的函数请参考:C++API之algorithm。

sort()基本使用方法

sort()函数可以对给定区间所有元素进行排序。它有三个参数sort(begin, end, cmp),其中begin为指向待sort()的数组的第一个元素的指针end为指向待sort()的数组的最后一个元素的下一个位置的指针cmp参数为排序准则,cmp参数可以不写,如果不写的话,默认从小到大进行排序。如果我们想从大到小排序可以将cmp参数写为greater()就是对int数组进行排序,当然<>中我们也可以写double、long、float等等。如果我们需要按照其他的排序准则,那么就需要我们自己定义一个bool类型的函数来传入。比如我们对一个整型数组进行从大到小排序:

#include<iostream>
#include<algorithm>
using namespace std;

int main(){
    int num[10] = {6,5,9,1,2,8,7,3,4,0};
    sort(num,num+10,greater<int>());
    for(int i=0;i<10;i++){
        cout<<num[i]<<" ";
    }//输出结果:9 8 7 6 5 4 3 2 1 0

    return 0;
}

自定义排序准则

上面我们说到sort()函数可以自定义排序准则,以便满足不同的排序情况。使用sort()不仅仅可以从大到小排或者从小到大排,还可以按照一定的准则进行排序。比如说我们按照每个数的个位进行从大到小排序,我们就可以根据自己的需求来写一个函数作为排序的准则传入到sort()中

我们可以将这个函数定义为:

bool cmp(int x,int y){
    return x % 10 > y % 10;
}

然后我们将这个cmp函数作为参数传入sort()中即可实现了上述排序需求。

按照每个数的个位进行从大到小排序

#include<iostream>
#include<algorithm>
using namespace std;

bool cmp(int x,int y){
    return x % 10 > y % 10;
}

int main(){
    int num[10] = {65,59,96,13,21,80,72,33,44,99};
    sort(num,num+10,cmp);
    for(int i=0;i<10;i++){
        cout<<num[i]<<" ";
    }//输出结果:59 99 96 65 44 13 33 72 21 80 
    return 0;   
}

对结构体进行排序

sort()也可以对结构体进行排序,比如我们定义一个结构体含有学生的姓名和成绩的结构体Student,然后我们按照每个学生的成绩从高到底进行排序。首先我们将结构体定义为:

struct Student{
    string name;
    int score;
    Student() {}
    Student(string n,int s):name(n),score(s) {}
};

根据排序要求我们可以将排序准则函数写为:

bool cmp_score(Student x,Student y){
    return x.score > y.score;
}

完整代码:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

struct Student{
    string name;
    int score;
    Student() {}
    Student(string n,int s):name(n),score(s) {}
};

bool cmp_score(Student x,Student y){
    return x.score > y.score;
}

int main(){
    Student stu[3];
    string n;
    int s;
    for(int i=0;i<3;i++){
        cin>>n>>s;
        stu[i] = Student(n,s);
    }

    sort(stu,stu+3,cmp_score);

    for(int i=0;i<3;i++){
        cout<<stu[i].name<<" "<<stu[i].score<<endl;
    }

    return 0;
}

再比如每一个学生有四科成绩,我们需要根据学生的四科成绩的平均分高低进行排名,那么这个cmp函数我们就可以定义为:

bool cmp_score(Student x,Student y){
    double average_x,average_y;
    average_x = (x.score[0]+x.score[1]+x.score[2]+x.score[3])/4;
    average_y = (y.score[0]+y.score[1]+y.score[2]+y.score[3])/4;
    return average_x > average_y;
}

完整代码:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

struct Student{
    string name;
    double score[4];
};

bool cmp_score(Student x,Student y){
    double average_x,average_y;
    average_x = (x.score[0]+x.score[1]+x.score[2]+x.score[3])/4;
    average_y = (y.score[0]+y.score[1]+y.score[2]+y.score[3])/4;
    return average_x > average_y;
}

int main(){
    Student stu[3];
    string n;
    int s;
    for(int i=0;i<3;i++){
        cin>>stu[i].name;
        for(int j=0;j<4;j++){
            cin>>stu[i].score[j];
        }
    }

    sort(stu,stu+3,cmp_score);

    for(int i=0;i<3;i++){
        cout<<stu[i].name<<" ";
        for(int j=0;j<4;j++){
            cout<<stu[i].score[j]<<" ";
        }
        cout<<endl;
    }

    return 0;
}

关于sort()函数的有关问题

今天在做牛客网的一个编程题的时候,出现了这个问题:reference to non-static member function must be called!

代码如下:

//二叉搜索树的先序遍历就是从小到大排序的,先保存二叉搜索树的先序遍历,然后找出第k个的数
class Solution {
public:
    TreeNode* KthNode(TreeNode* pRoot, int k)
    {
        fun(pRoot);   //先序遍历
        int len = num.size();
        if(len == 0 || k > len)
            return NULL;
        sort(num.begin(),num.end(),com);    //排序
        for(int i=0;i<k;i++)
        {
            if(i == k-1)
                return num[k-1];
        }
        return NULL;
    }

    //先序遍历的非递归实现
    void fun(TreeNode* pRoot)
    {
        stack<TreeNode*> s;//辅助栈
        TreeNode* pNode = pRoot;
        while(pNode)
        {
            s.push(pNode);
            num.push_back(pNode);   //保存节点
            pNode = pNode->left;    //往左子树转移
        }

        while(!s.empty())
        {
            TreeNode* tempNode = s.top();  //取当前栈顶元素
            s.pop();
            if(tempNode->right)   //如果有右子树
            {
                TreeNode* t = tempNode->right;
                while(t)
                {
                    num.push_back(t);   //保存当前节点右子树
                    s.push(t);
                    t = t->left;   //往左子树转移
                }
            }
        }
    }

    static bool com(TreeNode* p1,TreeNode* p2)    //谓词
    {
        return p1->val < p2->val;
    }
public:
    vector<TreeNode*> num;   //存储先序遍历
};

首先说明问题意思:这个问题是指你引用(调用)了非静态函数,但你不是通过类对象来调用的。问题的来源就是sort()函数的第三个谓词参数。为什么会是这样的呢?

按照常理来说,同一个类的非静态const成员函数中能相互调用,而不用通过类对象进行访问,为什么这里不行呢?相反如果我们把谓词函数com()定义为static函数问题就没有了。

问题的原因其实就是函数参数不匹配的问题。因为我们普通的成员函数都有一个隐含的this指针,表面上看我们的谓词函数com()只有两个参数,但实际上它有三个参数,而我们调用sort()排序函数的时候只需要用到两个参数进行比较,所以就出现了形参与实参不匹配的情况(函数有三个形参,但是只输入了两个实参)。

所以,解决办法就是把谓词函数com()定义为static成员函数。
原文链接: https://www.cnblogs.com/zhjblogs/p/15948078.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/188039

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午1:57
下一篇 2023年2月12日 下午1:57

相关推荐