qsort函数和qsort函数的模拟实现
一,qsort函数的实现
#define _CRT_SECURE_NO_WARNINGS 1 //qsort函数 #include<stdio.h> #include<stdlib.h> void print(int arr[], int sz) { for (int i = 0; i < sz; i++) printf("%d ",arr[i]); printf("\n"); } int compare(const void *e1,const void *e2) { return *(int*)e1 - *(int*)e2; } int main() { int arr[] = { 9,8,7,6,5,4,3,2,1,0 }; int sz = sizeof(arr) / sizeof(arr[0]); //排序 qsort(arr,sz,sizeof(arr[0]),compare); //输出 print(arr, sz); return 0; } //qsort函数的基本结构(快速排序) //void qsort(void* base, size_t num, size_t size, int (*compare)(const void*, const void*)); //void* base指的是排序数据首元素的地址。 //size_t num指的是排序数据的个数; //size_t size指的是每个元素的大小(占几个字节);因为传进来的数据首元素的类型未知,需要认为的输入字节大小; //int (*compare)(const void*, const void*)指的是一个函数指针;指向一个函数。这个是留给使用者写的自定义函数。 //因为qsort函数适用于所有类型的比较排序,所以指针类型都是void,但是使用者是一定知道比较的数据类型,故把这个函数留给使用者写 // //int compare(const void* e1, const void* e2) { // return *(int*)e1 - *(int*)e2; //} //我们来分析一下这个该由我们自己书写的函数 //首先,参数是两个无类型的空指针,代表着这个函数可以用于任何类型的数据相比较 //这个函数的返回值一定是int整型,因为在qsort函数中是根据这个函数的返回值进行排序的,返回值大于0是就是升序排序, //返回值小于0就是降序排序。
qsort函数的基本结构(快速排序)
void qsort(void* base, size_t num, size_t size, int (*compare)(const void*, const void*));
void* base指的是排序数据首元素的地址。
size_t num指的是排序数据的个数;
size_t size指的是每个元素的大小(占几个字节);因为传进来的数据首元素的类型未知,需要认为的输入字节大小;
int (*compare)(const void*, const void*)指的是一个函数指针;指向一个函数。这个是留给使用者写的自定义函数。
因为qsort函数适用于所有类型的比较排序,所以指针类型都是void,但是使用者是一定知道比较的数据类型,故把这个函数留给使用者写
int compare(const void* e1, const void* e2) {
return *(int*)e1 - *(int*)e2;
}
我们来分析一下这个该由我们自己书写的函数
首先,参数是两个无类型的空指针,代表着这个函数可以用于任何类型的数据相比较
这个函数的返回值一定是int整型,因为在qsort函数中是根据这个函数的返回值进行排序的,返回值大于0是就是升序排序,
返回值小于0就是降序排序。
二,qsort函数的模拟实现
//模拟实现qsort函数 #include<stdio.h> //交换函数(也可以不单独写成函数,但是我觉得主要可读性更好) void swap(char* buf1, char* buf2,size_t width) { int i; for (i = 0; i < width; i++) { char temp = *buf1; *buf1 = *buf2; *buf2 = temp; buf1++; buf2++; } } //写qsort必须写的函数,必须由使用者写,虽然我们这里是模拟实现qsort函数,但是仍需要写这个。 int compare(const void* e1, const void* e2) { //根据返回值进行排序(来绝对是升序还是降序) return *(char*)e1 - *(char*)e2; } void bubble_sort(void* base, size_t sz, size_t width, int (*compare)(const void*, const void*)) { int i, j; //外层循环控制总趟数 for (i = 0; i < sz-1; i++) {//这里一定是sz减一,sz是数组长度,下标只能到sz-1; for (j = 0; j < sz - i- 1; j++) { //这个地方是妥妥的重点了,为什么要强制类型转换为char* 类型? //其实这个地方我觉得转换为其他类型也行,但是qsort函数是可以对所有数据类型进行排序的,如果只是对单一的一种数据排序,那的确是可以的 //但是我们这里是模拟实现qsort函数的功能,故,我们这里转换为char* 类型 //还有一个原因,char*类型的指针解引用时只走一个字节,众所周知,字节是代码的最小存储单位了,其他无论什么类型的数据都是以字节论的 if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0) swap(((char*)base + j * width), ((char*)base + (j + 1) * width),width); //我们再来理解一下这个(char*)base + j * width是什么意思呢? //首先这个char*我是已经将过了的,接下来我们要解释的就是j*width的含义 //因为我们对未知类型的数据进行排序,(int*)+1是走四个字节,但对它本身来说就只移动了一个元素长度 //那如果是(int*)+i呢?我们是不是就可以理解为从头开始往后面走了i个元素,拿这个例子与上面一对比,这就十分明确了 //j*width的意思就是待排序数据一个元素所占用的长度,也就是往后面移动了一位。 } } } int main() { int arr[] = { 1,3,5,7,9,2,4,6,8,0 }; bubble_sort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), compare); int i = 0; for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { printf("%d",arr[i]); } printf("\n"); char arr1[] = "hello world";//这里我准备了两个例子供大家参考 bubble_sort(arr1, sizeof(arr1) / sizeof(arr1[0]), sizeof(arr1[0]), compare); for (i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++) printf("%c",arr1[i]); printf("\n"); return 0; }
qsort函数,俗称快排,它可以对任意数据类型的数据进行排序,这是很方便的,希望大家一定要搞熟。
希望大家能学到东西,静待大家的斧正和指教。