C函式庫qsort函式及最後一個引數的相關問題
在學習資料結構的時候,我們會學習到很多不同的排序演算法,比如說氣泡排序法,雜湊表(大霧),以及快速排序。而C的函式庫也給我們了一個快速排序的函式。就是我所提到的這個qsort。這個函式內部是一個寫好了的快速排序演算法的函式。標頭檔案是#include<stdlib.h>。
我們首先需要來了解一下什麼是快速排序,快速排序可以說是一種基於氣泡排序的衍生演算法,它是對於氣泡排序的一種改進。快速排序法是最有效的排序演算法之一,對大型陣列而言更是如此。它的基本思想是,通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小,則可以對這兩部分記錄繼續進行排序,不斷縮小資料結構,不斷重複這個過程,以達到整個序列有序。這個演算法我們會在我的另一個新篇(新坑)的資料結構中進行說明。我們今天要說明的是qsort()快速排序的這個演算法。在ANSI原形中
void qsort(void *base,size_t nmemb,size_t size,int (*compar)(const void *,const void *));
猛一看,這個原形還是讓人耳目一新啊(大霧)。分析一下這個函式所需要的引數:第一個引數為指向要排序的陣列頭部的指標。因為我們並不能夠確定我們要排的序列的型別,是整形,浮點數,亦或是字串。所以這裡使用的是無符號指標,這樣qsort函式的第一個十級引數可以指向任何型別的陣列。第二個引數為需要排序的專案量,也就是我們要進行排序的資料的多少。函式原型將該值轉換為size_t型別 ,並在標準標頭檔案中定義該整數型別。(size_t型別是sizeof返回的型別的值。這是一個無符號整數型別,但它不是一個新的型別,相反與可移植型別相同,它是根據你標準型別定義的。它與typedef的使用有些相似,舉個栗子,C的標頭檔案系統可以使用typedef來使size_t在系統中作為unsigned
int 啊 double之類的同義詞。這樣當我們使用size_t的時候,編譯器就會使用適合我們系統的標準型別代替。)第三個引數則是我們需要傳入我們需要警醒快速排序的引數的單獨元素的大小,因為qsort()將第一個引數轉換為void指標,所以會失去每個陣列元素的大小資訊,為補充這部分資訊,必須把資料物件的大小明確地告訴qsort()。這就是第三個引數的作用。舉個栗子,對int陣列排序,就必須使用sizeof(int)作為第三個引數。
最後,qsort()還需要一個指向函式的指標,被指向的函式用於確定排序順序,可以簡單理解一下就是我們要怎麼排序這個陣列,是從小到大亦或是從大到小,都可以修改這裡的引數進行實現。這個比較函式接受兩個引數,就是分別指向進行比較的兩個專案的指標。For example如果第一個專案的值大於第二個專案的值,那麼比較函式返回正數;值相等返回值為0;相反則返回負數。qsort()根據給定的其他資訊計算出兩個指標值,然後把它們傳遞給該比較函式。這個引數實際上是一個函式。需要我們自己在使用的時候進行編寫。我們單獨把這個引數拿出來
int (*compar)(const void*,const coid*)
這表示最後的引數是個指向函式的指標,該函式返回Int值並接受兩個引數,二每個引數均為指向const
void型別的指標,const提醒我們這兩個引數不能修改。這兩個指標指向需要比較的專案。
整形排序的compar
int cmp ( const void *a , const void *b )
{
return *(int *)a - *(int *)b; //升序排序
//return *(int *)b - *(int *)a; //降序排序
字串型別的compar
int cmp( const void *a , const void *b )
{
return *(char *)a - *(char *)b;
//return *(char *)a - *(char *)b;
} double型別的comparint cmp( const void *a , const void *b )
{
return *(double *)a > *(double *)b ? 1 : -1;
} 結構體型別的compar int cmp( const void *a ,const void *b) {struct In *aa = (In *)a; struct In *bb = (In *)b; return aa->data > bb->data ? 1 : -1;
}
這些就是一些比較常用的compar引數的設定。相對的在研究qsort的函式的同時,我也模仿著寫了一個類似快速排序的氣泡排序
1
#include<stdio.h>
#include<windows.h>
#include<assert.h>
void bubble_char(void *data,int nums,int width,int(*comp)(void *,void*))
{
int i=0;
int k =0;
int j=0;
int flag =0;
assert(data);
for(;i<nums-1;i++)
{
char *start=(char*)data;
for(;j<nums-1;j++)
{
if(comp(start,start+width)>0)
for(;k<width;k++)
{
start[k]^=start[k+width];
start[k+width]^=start[k];
start[k]^=start[k+width];
}
flag=1;
}
start+=width;
if(!flag){
break;
}
}
}
int comp(void *x,void*y)
{
char*a=(char*)x;
char*b=(char*)y;
return *a-*b;
}
int main()
{
char arr[]="hello world ";
int len = sizeof(arr)/sizeof(arr[0]);
bubble_char(arr,len,sizeof(char),comp);
printf("%s",arr);
system("pause");
return 0;
}
這個便是使用了快速排序的氣泡排序來排序字串型別的大小。也就是個字母排列。有興趣的童鞋不妨試一試。如有問題 請各位大佬們指出。