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函数,俗称快排,它可以对任意数据类型的数据进行排序,这是很方便的,希望大家一定要搞熟。
希望大家能学到东西,静待大家的斧正和指教。