qsort()函数(quick sort)是八大排序算法中的快速排序,能够排序任意数据类型的数组其中包括整形,浮点型,字符串甚至还有自定义的结构体类型。
我们分析一下它的参数:
base:它指向需要排序的首元素的地址,是一个void*的指针;
num:需要排序的元素个数;
size:每个元素的大小;
int (*compar)(const void*, const void*):这是一个函数指针,这个函数指针指向的函数,能够比较base指向的数组中相邻两个元素的大小。(需要自己设计)
注意:
- 使用这个函数要包含的头文件是:
#include<stdlib.h>
- 此函数默认是从小到大排序。
举个例子:
#include<stdio.h>
#include<stdlib.h>
int compar(const void* p1, const void* p2)
{
return *((int*)p1) - *((int*)p2);
}
void print(int* p, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
printf("\n");
}
int main()
{
int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(int), compar);
print(arr, sz);
return 0;
}
这里我们比较的是整形数据,所以compar函数的指针就要强转成int*再解引用。
也可以比较字符串,比较结构体类型的数据,其主要就是在compar函数里看情况设计。
我们再举个例子,比如比较结构体类型的字符串:
struct stu
{
char name[5];
int age;
};
compar函数可以这样设计
int compar(const void* p1, const void* p2)
{
return strcmp((struct stu*)p1->name, (struct stu*)p2->name);
}
懂了它的原理,我们开始模拟实现:
我们需要解决的地方主要有三:
- 解决1:void*指针,元素个数,元素大小
- 解决2:将两个元素比较方法,用函数参数的形式传递
- 解决3:不同的数据类型,交换略有差异
首先我们得有主函数,就跟上面的例子一样。
int main()
{
int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble(arr, sz, sizeof(int), compar);
print(arr, sz);
return 0;
}
然后就是bubble函数的实现啦:
首先设计它的返回类型,函数参数,因为是模拟实现嘛,就跟它原本的差不多啦。
void* bubble(void* base, size_t num, size_t size, int (*compar)(const void*, const void*))
它的基本思想是通过不断比较相邻的元素,将较大的元素向后移动,较小的元素向前移动,从而实现排序的目的。
一趟排一个元素,只剩最后一个元素的时候已经不用排序了,所以趟数就是要比较的元素个数减1。确定之后就是比较相邻元素的大小了,我们就设计compar这个函数比较,小的在前大的在后,不符合就交换,所以还需要设计一个函数帮我们交换。
以上就是思路,具体实现一下:
void bubble(void* base, size_t num, size_t size, int (*cmp)(const void*, const void*))
{
int i = 0;
//趟数
for (i = 0; i < num - 1; i++)
{
int j = 0;
//一趟比较的对数
for (j = 0; j < num - 1 - i; j++)
{
//比较两个相邻元素,要将数组的第一个元素和第二个元素地址传进去
if (compar((char*)base + j * size, (char*)base + (j + 1) * size) > 0)//因为类型不确定,要强转成最小的类型char*再加j乘以类型大小,就是跳过几个字节
{
//交换
swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
}
}
}
}
然后是compar函数:
注意这里是根据你要比较的类型确定强转成什么类型,而且到底是比较字符串还是数字这都是视情况来定的。(这里以int类型的数据比较)
int compar(const void* p1, const void* p2)
{
return *(int*)p1 - *(int*)p2;
}
比较之后,不符合小的在前的要交换,设计swap函数来帮我们实现:
void swap(char* buf1, char* buf2, size_t size)
{
int i = 0;
char tmp = 0;
for (i = 0; i < size; i++)//例如,一个整形四个字节,要一个一个交换,所以i < size
{
tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
这个函数要传两个需要交换的元素的地址,和字节大小。因为要交换的类型不确定,只能一个字节一个字节交换,我们用char*的指针。
以上整体就是实现的具体方法。