C++中sort()函數使用介紹


sort()簡介

為什么選擇使用sort() 

在刷題的時候我們經常會碰到排序的問題,如果我們不使用一些排序的方法那我們只能手撕排序,這樣就會浪費一些時間。而且我們還需要根據需要去選擇相關的排序方法:冒泡排序、快速排序、插入排序、希爾排序、歸並排序、選擇排序、堆排序、基數排序、桶排序。在選擇的過程中也需要我們花費一些時間,所以在明白這些經典排序的情況下再一遍一遍的手寫就有點浪費時間啦!
 如果我們使用sort()方法就可以只需要一條語句就可以實現排序,這樣就極大的節省了我們在刷題中所花費的時間。當然如果對這些經典的排序方法不熟悉的話還是建議大家去了解一下這些方法,比較一下這些方法的優劣以及使用的情景。

sort()函數的實現原理

也許你會疑問,我使用sort方法對數據進行排序就一定合適嗎?sort()可以根據我的需要對數據進行排序嗎?其實sort()函數還是一個比較靈活的函數。很多解釋是:sort()函數是類似於快速排序的方法,時間復雜度為n*log2(n),執行效率較高。
 其實STL中的sort()並非只是普通的快速排序除了對普通的快速排序進行優化,它還結合了插入排序和堆排序。根據不同的數量級別以及不同情況,能自動選用合適的排序方法。當數據量較大時采用快速排序,分段遞歸。一旦分段后的數據量小於某個閥值,為避免遞歸調用帶來過大的額外負荷,便會改用插入排序。而如果遞歸層次過深,有出現最壞情況的傾向,還會改用堆排序。所以說sort()是一個比較靈活的函數,它也會根據我們數據的需要進行排序,所以我們就不用擔心以上的問題了。對於大部分的排序需求,sort()都是可以滿足的。

sort()的使用方法

頭文件 

在C++中使用sort()函數需要使用#include<algorithm>頭文件。algorithm意為"算法",是C++的標准模版庫(STL)中最重要的頭文件之一,提供了大量基於迭代器的非成員模版函數。該頭文件的詳細使用方法以及包含的函數請參考:C++API之algorithm。

sort()基本使用方法

sort()函數可以對給定區間所有元素進行排序。它有三個參數sort(begin, end, cmp),其中begin為指向待sort()的數組的第一個元素的指針end為指向待sort()的數組的最后一個元素的下一個位置的指針cmp參數為排序准則,cmp參數可以不寫,如果不寫的話,默認從小到大進行排序。如果我們想從大到小排序可以將cmp參數寫為greater<int>()就是對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成員函數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM