1. 程式人生 > >C語言qsort解析

C語言qsort解析

第一篇

qsort(基本快速排序的方法,每次把陣列分成兩部分和中間的一個劃分值,而對於有多個重複值的陣列來說,基本快速排序的效率較低,且不穩定)。整合在C語言庫函式裡面的的qsort函式,使用 三 路劃分的方法解決排序這個問題。所謂三路劃分,是指把陣列劃分成小於劃分值,等於劃分值和大於劃分值的三個部分。

具體介紹:-^^

voidqsort( void *base, size_t num, size_t width, int (__cdecl *compare )

intcompare (const void *elem1, const void *elem2 ) );

qsort(即,quicksort)主要根據你給的比較條件給一個快速排序,主要是通過指標移動實現排序功能。排序之後的結果仍然放在原來陣列中。

引數意義如下:

第一個引數 base 是 需要排序的目標陣列名(或者也可以理解成開始排序的地址,因為可以寫&s[i]這樣的表示式)

第二個引數 num 是 參與排序的目標陣列元素個數

第三個引數 width 是單個元素的大小(或者目標陣列中每一個元素長度),推薦使用sizeof(s[0])這樣的表示式

第四個引數 compare 就是讓很多人覺得非常困惑的比較函式啦。

我們來簡單討論compare這個比較函式(寫成compare是我的個人喜好,你可以隨便寫成什麼,比如 cmp 什麼的,在後面我會一直用cmp做解釋)。

典型的compare的定義是int compare(const void *a,constvoid *b);

返回值必須是int,兩個引數的型別必須都是const void *,那個a,b是隨便寫的,個人喜好。假設是對int排序的話,如果是升序,那麼就是如果a比b大返回一個正值,小則負值,相等返回0,其他的依次類推,後面有例子來說明對不同的型別如何進行排序。

qsort的使用方法:

一、對int型別陣列排序

int num[100];

int cmp ( const void *a , const void *b )

{

  return *(int *)a - *(int *)b;  //升序排序

//return*(int *)b - *(int *)a; //降序排序

/*可見:引數列表是兩個空指標,現在他要去指向你的陣列元素。所以轉型為你當前的型別,然後取值。

        升序排列時,若第一個引數指標指向的“值”大於第二個引數指標指向的“值”,則返回正;若第一個引數指標指向的“值”等於第二個引數指標指向的“值”,則返回零;若第一個引數指標指向的“值”小於第二個引數指標指向的“值”,則返回負。

        降序排列時,則剛好相反。

*/

}

qsort(s,n,sizeof(s[0]),cmp);

示例完整函式(已在 VC6.0上執行通過):

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

int s[10000],n,i;

int cmp(const void *a,const void *b)

{

return(*(int*)b-*(int *)a);  //實現的是升序排序

}

int main()

{

//輸入想要輸入的數的個數

scanf("%d",&n);

for(i=0;i<n;i++)

scanf("%d",&s[i]);

qsort(s,n,sizeof(s[0]),cmp);

for(i=0;i<n;i++)

printf("%d",s[i]);

return(0);

}

二、對char型別陣列排序(同int型別)

char word[100];

int cmp( const void *a , const void *b )

{
return*(char *)a - *(char *)b;

}

qsort(word,100,sizeof(word[0]),cmp);

//附,可能getchar(); 會派上用場

三、對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);

//附:排序結果的輸出,一般建議用 “ %g ” 格式

四、對結構體一級排序

struct In

{

double data;

int other;

}s[100]


 


int cmp( const void *a ,const void *b)

{

return(*(In *)a).data > (*(In *)b).data ? 1 : -1;

//或者你可以將這上面1條語句改成下面這3條語句

//structIn *aa = (In *)a;

//structIn *bb = (In *)b;

//returnaa->data > bb->data ? 1 : -1;

}

qsort(s,100,sizeof(s[0]),cmp);

五、對結構體二級排序

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

六、對字串進行排序

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

 

注意!qsort 中的 cmp 得自己寫 。

再說說 sort (常用於 C++ )

sort使用時得註明:using namespace std; 或直接打 std::sort() 還得加上 #include 標頭檔案

例:

#include<iostream>

#include<algorithm>

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

     return0;

}

std::sort是一個改進版的qsort. std::sort函式優於qsort的一些特點:對大陣列採取9項取樣,更完全的三路劃分演算法,更細緻的對不同陣列大小採用不同方法排序。

最後,我們來說說sort、qsort的區別:

sort是qsort的升級版,如果能用sort儘量用sort,使用也比較簡單,不像qsort還得自己去寫 cmp 函式,只要註明 使用的庫函式就可以使用,引數只有兩個(如果是普通用法)頭指標和尾指標;

預設sort排序後是升序,如果想讓他降序排列,可以使用自己編的cmp函式

#include<iostream>

#include<algorithm>

usingnamespace std;

int cmp(int a,int b)

{

  if(a<b)

  return 1; //升序排列,如果改為 a >b,則為降序,要注意sort()中cmp()的返值只有1和0,不像qsort中存在-1!!!!

  else

  return 0;

}

 

int main(){

       int i;

 int a[20];

 for(int i=0;i<5;++i)

  cin>>a[i];

sort(a,a+5,cmp);          //範圍,很明顯這裡是a+5 注意,這是必要的,如果是a+4最後一個值a[4]就不會參與排序。

for(i=0;i<5;i++)      

cout<<a[i]<<endl;

       system("pause");

 return 0;

}

對二維陣列的排序:

#include<iostream>

#include<algorithm>

#include<ctime>

usingnamespace std;

 

bool cmp(int *p,int *q)

{

       if(p[0]==q[0])

       {

           if(p[1]==q[1])

           {

               return p[2]<q[2];

           }

           else return p[1]<q[1];

       }

       else return p[0]<q[0];

}

int main()

{

       srand(time(0));

       int i;

       int **a=new int*[1000];

       for(i=0;i<1000;++i)

       {

           a[i]=newint[3];

           a[i][0]=rand()%1000;

           a[i][1]=rand()%1000;

           a[i][2]=rand()%1000;

           //printf("%d\t%d\t%d\n",a[i][0],a[i][1],a[i][2]);

       }

       sort(a,a+1000,cmp);

       /*cout<<"Aftersort"<<endl;

       for(i=0;i<1000;++i)

       {

           printf("%d\t%d\t%d\n",a[i][0],a[i][1],a[i][2]);

       }*/

       return 0;

}

第二篇

C語言標準庫函式 qsort詳解
qsort包含在<stdlib.h>標頭檔案中,此函式根據你給的比較條件進行快速排序,通過指標移動實現排序。排序之後的結果仍然放在原陣列中。使用qsort函式必須自己寫一個比較函式。

函式原型:

void qsort ( void * base, size_tnum, size_t size, int ( * comparator ) ( const void *, const void * ) );

指向任意資料型別的指標都可以轉換為void*型別

用法以及引數說明:
Sortsthe num elements of the array pointed by base, each element size bytes long,using the comparator function to determine the order.

   Thesorting algorithm used by this function compares pairs of values by calling thespecified comparator function with two pointers to elements of the array.

   Thefunction does not return any value, but modifies the content of the arraypointed by base reordering its elements to the newly sorted order.

   basePointer to the first element of the array to be sorted.(陣列起始地址)

   numNumber of elements in the array pointed by base.(陣列元素個數)

   sizeSize in bytes of each element in the array.(每一個元素的大小)

   comparatorFunction that compares two elements.(函式指標,指向比較函式)

1、The function must accept two parameters that are pointers to elements,type-casted as void*. These parameters should be cast back to some data typeand be compared.

2、The return value of this function should represent whether elem1 isconsidered less than, equal to, or greater than elem2 by returning,respectively, a negative value, zero or a positive value.

Return Value none (無返回值)

   給你們的C++幫助文件上面的語法及定義是:

語法:

#include <stdlib.h>

void qsort( void *buf, size_t num, size_t size, int (*compare)(const void *, const void *) );

功能: 對buf 指向的資料(包含num 項,每項的大小為size)進行快速排序。如果函式compare 的第一個引數小於第二個引數,返回負值;如果等於返回零值;如果大於返回正值。函式對buf 指向的資料按升序排序。

關鍵比較函式

一、對int型別陣列排序

int num[100];

int cmp ( const void *a , const void *b )
{
      return *(int *)a - *(int *)b;
}

 

 

////qsort對int型別的陣列排序

#include<iostream>

using namespace std;

 

int num[100];

int cmp(const void* a,const void* b)

{

    return*(int*)a - *(int*)b;

}

int main()

{

    intn,i;

    cout<<"請輸入陣列大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i];

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i]<<endl;

       else

           cout<<num[i]<<" ";

    }

    return0;

}

二、對char型別陣列排序(同int型別)

char word[100];

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

qsort(word,100,sizeof(word[0]),cmp);

 

注:按ASCII碼排序,類似int

////qsort對char型別的陣列排序

#include<iostream>

using namespace std;

 

char num[100];

int cmp(const void* a,const void* b)

{

    return*(char*)a - *(char*)b;

}

int main()

{

    intn,i;

    cout<<"請輸入陣列大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i];

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i]<<endl;

       else

           cout<<num[i]<<" ";

    }

    return0;}

三、對double型別陣列排序

double in[100];

int cmp( const void *a , const void *b )
{
      return *(double *)a > *(double*)b ? 1 : -1;
}

qsort(in,100,sizeof(in[0]),cmp);

 

 

 

////qsort對double型別的陣列排序

#include<iostream>

using namespace std;

 

double num[100];

int cmp(const void* a,const void* b)

{

    return*(double*)a - *(double*)b;

}

int main()

{

    intn,i;

    cout<<"請輸入陣列大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i];

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i]<<endl;

       else

           cout<<num[i]<<" ";

    }

       return 0;}

 

 

 

四、對結構體一級排序
struct Sample

{

    doubledata;

    intother;

}s[100];

 

//按照data的值從小到大將結構體排序

int cmp( const void *a ,const void *b)

{

    return(*(Sample *)a).data > (*(Sample *)b).data ? 1 : -1;

}

 

qsort(s,100,sizeof(s[0]),cmp);

 

////程式

////qsort對結構型別的陣列一級排序

#include<iostream>

using namespace std;

 

struct Sample

{

    intdata;

    charother;

};

 

Sample num[100];///結構陣列

 

int cmp(const void* a,const void* b)

{

    return((Sample*)a)->data - ((Sample*)b)->data;

    //return(*(Sample*)a).data - (*(Sample*)b).data;也行的,一個是解引用,一個是直接指標指向

}

int main()

{

    intn,i;

    cout<<"請輸入陣列大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i].data>>num[i].other;

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i].data<<" "<<num[i].other<<endl;

       else

           cout<<num[i].data<<" "<<num[i].other<<" ";

    }

    return0;

}

五、對結構體二級排序
 

struct Sample

{

int x;

int y;

}s[100];

 

//按照x從小到大排序,當x相等時按照y從大到小排序

 

int cmp( const void *a , const void *b )

{

    structSample *c = (Sample *)a;

    structSample *d = (Sample *)b;

    if(c->x!= d->x)

       returnc->x - d->x;

    else

       return d->y - c->y;

}

 

qsort(s,100,sizeof(s[0]),cmp);

 

 

 

////qsort對結構型別的陣列二級排序

#include<iostream>

using namespace std;

 

struct Sample

{

    intdata;

    charother;

};

Sample num[100];///結構陣列

int cmp(const void* a,const void* b)

{

    Sample *c = (Sample*)a;

    Sample *d = (Sample*)b;

    if(c->data== d->data)

       returnc->other - d->other;////如果結構體中的data相等則執行第二級排序

    else

       returnc->data - d->data;

}

int main()

{

    intn,i;

    cout<<"請輸入陣列大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i].data>>num[i].other;

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i].data<<" "<<num[i].other<<endl;

       else

           cout<<num[i].data<<" "<<num[i].other<<" ";

    }

    return0;

}

六、對字串進行排序

struct Sample

{

    intdata;

    charstr[100];

}s[100];

 

//按照結構體中字串str的字典順序排序

int cmp ( const void *a , const void *b )

{

    returnstrcmp( (*(Sample *)a)->str , (*(Sample *)b)->str );

}

qsort(s,100,sizeof(s[0]),cmp);

////對字串進行排序

#include<iostream>

using namespace std;

struct Sample

{

    charch[100];

};

Sample num[100];///結構陣列

int cmp(const void* a,const void* b)

{

    returnstrcmp( ((Sample*)a)->ch,((Sample*)b)->ch );

}

int main()

{

    intn,i;

    cout<<"請輸入陣列大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i].ch;

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i].ch<<endl;

       else

           cout<<num[i].ch<<" ";

    }

    return0;

}

附加一個完整點的程式碼,對字串二維陣列排序:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

char s[2001][1001];

 

int cmp(const void *a, const void *b){

    returnstrcmp((char *)a,(char*)b);

}

 

int main(){

    inti,n;

    scanf("%d",&n);

    getchar();

    for(i=0;i<n;i++)

           gets(s[i]);

    qsort(s,n,1001*sizeof(char),cmp);

    for(i=0;i<n;i++)

           puts(s[i]);

    return0;

}

Sort()函式類似,不再一步一步舉例,可以自學了
2、sort()
sort 對給定區間所有元素進行排序

stable_sort 對給定區間所有元素進行穩定排序

partial_sort 對給定區間所有元素部分排序

partial_sort_copy 對給定區間複製並排序

nth_element 找出給定區間的某個位置對應的元素

is_sorted 判斷一個區間是否已經排好序

partition 使得符合某個條件的元素放在前面

stable_partition 相對穩定的使得符合某個條件的元素放在前面

語法描述為:

(1)sort(begin,end),表示一個範圍,例如:

i

nt _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按升序排序,說到這裡可能就有人會問怎麼樣用它降序排列呢?這就是下一個討論的內容。

(2)sort(begin,end,compare)

一種是自己編寫一個比較函式來實現,接著呼叫三個引數的sort:sort(begin,end,compare)就成了。對於list容器,這個方法也適用,把compare作為sort的引數就可以了,即:sort(compare)。

1)自己編寫compare函式:

bool compare(int a,int b)

{

 return a<b; //升序排列,如果改為return a>b,則為降序

}

int _tmain(int argc, _TCHAR* argv[])

{

  inta[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()

{

  inta[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、not_equal_to、greater、greater_equal、less、less_equal。對於這個問題來說,greater和less就足夠了,直接拿過來用:

升序:sort(begin,end,less());

降序:sort(begin,end,greater()).

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;

}