C/C++中有一个快速排序的标准库函数 qsort
,在stdlib.h
和cstdlib
中声明,其原型为:
void qsort(void *base, int nelem, unsigned int width, int ( * pfCompare)( const void *, const void *));
使用该函数,可以对任何类型的一维数组排序。
-
base
是待排序数组的起始地址; -
nelem
是待排序数组的元素个数; -
width
是待排序数组的每个元素的大小(以字节为单位); -
pfCompare
是一个函数指针,它指向一个“比较函数”。
排序就是一个不断比较并交换位置的过程。qsort
如何在连元素的类型是什么都不知道的情况下,比较两个元素并判断哪个应该在前呢?
答案是:qsort
函数在执行期间,会通过pfCompare
指针调用一个 “比较函数”,用以判断两个元素哪个更应该排在前面。这个“比较函数”不是C/C++的库函数,而是由使用qsort 的程序员编写的。在调用qsort
时, 将“比较函数”的名字作为实参传递给pfCompare
。程序员当然清楚该按什么规则决定哪个元素应该在前,哪个元素应该在后,这个规则就体现在“比较函数”中。
qsort
函数的用法规定,“比较函数”的原型应是:int 函数名(const void * elem1, const void * elem2)
;该函数的两个参数,elem1
和elem2
,分别指向待比较的两个元素。也就是说, * elem1
和* elem2
就是待比较的两个元素。该函数必须具有以下行为:
- 如果
* elem1
应该排在* elem2
前面,则函数返回值是负整数(任何负整数都行); - 如果
* elem1
和* elem2
哪个排在前面都行,那么函数返回0; - 如果
* elem1
应该排在* elem2
后面,则函数返回值是正整数(任何正整数都行)。
例如:
#include
#include
#include
using namespace std;
int compare(const void *a, const void *b)
{
int *pa = (int*)a;
int *pb = (int*)b;
return (*pa )- (*pb); //从小到大排序
}
void main()
{
int a[10] = {5, 6, 4, 3, 7, 0 ,8, 9, 2, 1};
qsort(a, 10, sizeof(int), compare);
for (int i = 0; i < 10; i++)
cout << a[i] << " " << endl;
}
再如:
下面的程序,功能是调用qsort
库函数,将一个unsigned int
数组按照个位数从小到大进行排序。比如 8,23,15 三个数,按个位数从小到大排序,就应该是 23,15,8:
#include
#include
int MyCompare( const void * elem1, const void * elem2
{
unsigned int * p1, * p2;
p1 = (unsigned int *) elem1; //语句6
p2 = (unsigned int *) elem2; //语句7
return (* p1 % 10) - (* p2 % 10 ); //语句8
}
#define NUM 5
int main()
{
unsigned int an[NUM] = { 8,123,11,10,4 };
qsort( an, NUM, sizeof(unsigned int), MyCompare);
for( int i = 0;i < NUM; i ++ )
printf("%d ", an[i]);
return 0;
}
上面程序的输出结果是:
10 11 123 4 8
qsort
函数执行期间,需要比较两个元素哪个应在前面时,就以两个元素的地址作为参数,调用 MyCompare
函数。如果返回值小于0,则qsort
就得知第一个元素应该在前,如果返回值大于0,则第一个元素应该在后。如果返回值等于0,则哪个在前都行。
对语句6 解释如下:由于elem1
是 const void *
类型的,是void
指针,那么表达式*elem1
是没有意义的。elem1
应指向待比较的元素,即一个unsigned int
类型的变量,所以要经过强制类型转换,将elem1
里存放的地址赋值给 p1
,这样,* p1
就是待比较的第一个元素了。语句7 同理。语句8 体现了排序的规则。如果 *p1 的个位数小于 *p2 的个位数,那么就返回负值。其他两种情况不再赘述。
转载链接:https://www.cnblogs.com/CCBB/archive/2010/01/15/1648827.html