淺談C++中qsort與sort的使用方法與區別
這兩天在刷leetcode時看到了一些關於排序的題目,其中遇到各種大神對sort與qsort的使用,個人在使用時對比發現了一些sort與qsort的區別,並對它們的使用方法進行了一些總結介紹。
在平時程式設計時,排序是一種經常要用到的操作。如果每次都自己臨場寫)排序演算法,不僅容易出錯,而且浪費寶貴的時間。在C++的STL裡面有兩個sort與qsort可以直接用於對各種型別的資料以及容器進行排序。
1、qsort
qsort函式定義在標頭檔案<algorithm>中,使用時需要include該標頭檔案
功 能: 使用快速排序例程進行排序
用 法: void qsort(void *base, int nelem, int width, int (*fcmp)(const void *,const void *));
引數:1、待排序陣列首地址; 2、陣列中待排序元素數量; 3、各元素的佔用空間大小; 4、指向函式的指標,用於確定排序的順序
比如:對一個長為1000的陣列進行排序時,int a[1000]; 那麼base應為a,num應為 1000,width應為 sizeof(int),cmp函式隨自己的命名。
使用方法:
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )
int compare (const void *elem1, const void *elem2 ) );
qsort(quicksort)主要根據你給的比較條件給一個快速排序,主要是通過指標移動實現排序功能。排序之後的結果仍然放在原來陣列中。
引數意義如下:
base:需要排序的目標陣列開始地址
num:目標陣列元素個數
width:目標陣列中每一個元素長度
compare:函式指標,指向比較函式(這個函式是要自己寫的,sort中預設升序)
(1)對int型別陣列排序
int num[100];
int cmp ( const void *a , const void *b )
{
return *(int *)a - *(int *)b;
}
可見:引數列表是兩個空指標,現在他要去指向你的陣列元素。所以轉型為你當前的型別,然後取值。升序排列。
qsort(num,100,sizeof(num[0]),cmp);
(2)對char型別陣列排序(同int型別)
char word[100];
int cmp( const void *a , const void *b )
{
return *(char *)a - *(int *)b;
}
qsort(word,100,sizeof(word[0]),cmp);
(3)對double型別陣列排序(特別要注意)
double in[100];
int cmp( const void *a , const void *b )
{
return *(double *)a > *(double *)b ? 1 : -1;
}
返回值的問題,顯然cmp返回的是一個整型,所以避免double返回小數而被丟失。
qsort(in,100,sizeof(in[0]),cmp);
(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(s[0]),cmp);
(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(s[0]),cmp);
(6)對字串進行排序
char str[100][100];
int cmp(const void* a,const void* b )
{
return strcmp((char *)a,(char*)b);
}
qsort(str,n,sizeof(str[0]),cmp);
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(s[0]),cmp);
2、sort
sort函式,與qsort同為排序函式,複雜度為n*log2(n)。sort()定義在標頭檔案<algorithm>中。sort函式是標準模板庫的函式,已知開始和結束的地址即可進行排序,可以用於比較任何容器(必須滿足隨機迭代器),任何元素,任何條件,執行速度一般比qsort要快。另外,sort()是類屬函式,可以用於比較任何容器,任何元素,任何條件。
注意:預設是升序排序。
sort 使用時得註明:using namespace std; 或直接打 std::sort() 還得加上 #include<algorithm>
例:
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int a[20];
for(int i=0;i<20;++i)
cin>>a[i];
sort(a,a+20); //範圍,很明顯這裡是a+20 注意,這是必要的,如果是a+19
for(i=0;i<20;i++) //最後一個值a[19]就不會參與排序。
cout<<a[i]<<endl;
return 0;
}
sort是qsort的升級版,如果能用sort儘量用sort,使用也比較簡單,不像qsort還得自己去寫 cmp 函式,只要註明 使用的庫函式就可以使用,引數只有兩個(如果是普通用法)頭指標和尾指標;
預設sort排序後是升序,如果想讓他降序排列,可以使用自己編的cmp函式
bool compare(int a,int b)
{
return a>b; //www.cdtarena.com降序排列,如果改為return a<b,則為升序
}
sort(*a,*b,cmp);
例子:
#include<iostream>
#include<algorithm>
using namespace std;
bool cmp (const int a, const int b)
{
return a > b;
}
int main()
{
int data[5];
for(int i = 0; i < 5; i++)
cin >> data[i];
sort(data, data + 5, cmp);
return 0;
}
sort函式可以傳兩個引數或三個引數。第一個引數是要排序的區間首地址,第二個引數是區間尾地址的下一地址。也就是說,排序的區間是[a,b)。簡單來說,有一個數組int a[100],要對從a[0]到a[99]的元素進行排序,只要寫sort(a,a+100)就行了,預設的排序方式是升序。 排序的資料型別不侷限於整數,只要是定義了小於運算的型別都可以,比如字串類string。如果是沒有定義小於運算的資料型別,或者想改變排序的順序,就要用到第三引數——比較函式。比較函式是一個自己定義的函式,返回值是bool型,它規定了什麼樣的關係才是“小於”。想把剛才的整數陣列按降序排列,可以先定義一個比較函式cmp:
bool cmp(int a,int b)
{
return a>b;
}
排序的時候就寫sort(a,a+100,cmp);
假設自己定義了一個結構體node:
struct node{
int a;
int b;
double c;
};
有一個node型別的陣列node arr[100],想對它進行排序:先按a值升序排列,如果a值相同,再按b值降序排列,如果b還相同,就按c降序排列。就可以寫這樣一個比較函式:
以下是程式碼片段:
bool cmp(node x,node y)
{
if(x.a!=y.a) return x.a
if(x.b!=y.b) return x.b>y.b;
return return x.c>y.c;
}
排序時寫sort(arr,a+100,cmp);
3、sort與qsort的對比
(1)最直觀的差別,函式形式不一樣,
qsort的使用方式為:
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )
sort的使用方式為:
template<classRandomAccessIterator>
voidsort ( RandomAccessIterator first, RandomAccessIterator last );
template<classRandomAccessIterator, classCompare>
voidsort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
sort有二個引數與三個引數版本,兩個引數預設升序排序,第三個引數可用於指定比較函式,調整排序方式。
(2)compare函式的寫法也是不一樣的。
qsort的compare函式寫法為:
int compare (const void *elem1, const void *elem2 ) );
sort的compare函式返回的是bool值;
(3)sort是一個改進版的qsort. std::sort函式優於qsort的一些特點:對大陣列採取9項取樣,更完全的三路劃分演算法,更細緻的對不同陣列大小採用不同方法排序。如果能用sort儘量用sort,使用也比較簡單,不像qsort還得自己去寫 cmp 函式,只要註明 使用的庫函式就可以使用,引數只有兩個(如果是普通用法)頭指標和尾指標;預設sort排序後是升序,如果想讓他降序排列,可以使用自己編的cmp函式