利用回调函数机制写万能排序函数
手写万能排序的思路:
假设自定义万能排序的函数名为:MyQSort
- 使用冒泡排序;
- 确定形参:
1)因为不知道传入到MyQSort中的是那种类型的数组,所以使用void* 无类型指针类型用于接收数组的首地址。
2)因为接收的是数组首地址,也不知道数组元素的数据类型,所需需要“数组的大小”和“数组元素的大小”
3)需传入一个比较器。能做到万能排序的原因,这是关键点。一种数据类型对应着一个比较器,用于比较两数组元素的大小,用于排序。 - 因为接收是数组的首元素地址,而且不知道数据类型。
1)换个思路来想,可以使用char类型的指针,获取每个元素的首地址,再加上指定的元素大小,就可以知道该数组元素在内存中的地址范围。
2)因此,就可以拿到该元素的所有数据,传入比较器后,将void类型强转所需类型即可正常比较。 - 然后根据冒泡排序的思想,如果前一个数组元素大于后一个,两个元素进行交换即可。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct People{
char name[20];
short age;
};
//交换两元素的内容。
//这里直接将实参(void*)强转成了char*,便于使用
void Swap(char*e1, char* e2, int weight){
int i = 0;
for (i = 0; i < weight; i++){
char temp = *(e1+i);
*(e1 + i) = *(e2 + i);
*(e2 + i) = temp;
}
}
//万能冒泡排序:
//data : 可以接收各种类型的数组
//size : 数组的元素个数
//weight : 每个元素的大小(相当于sizeof(arr[0])的大小
//cmp : 自定义比较大小的函数
void MyQSort(void* data, int size, int weight, int(*cmp)(const void* e1, const void * e2)){
//利用冒排序进行排序:
int i = 0;
for ( i = 0; i < size-1; i++)
{
int j = 0;
for (j = 0; j < size-i - 1; j++){
//以字节为单位,传递数组的每个首元素地址。然后根据元素的整体大小移步指针。
if (cmp(((char*)data + j*weight), ((char*)data + (j + 1)*weight)) > 0){
//交换两元素
Swap(((char*)data + j*weight), ((char*)data + (j + 1)*weight), weight);
}
}
}
}
//自定义比较器
int Mycmp_age(const void* e1, const void * e2){
struct People* a1 = (struct People *)e1;
struct People* a2 = (struct People *)e2;
return (a2->age) - (a1->age);
}
//打印函数
void Printfs(const struct People* arr,int size){
int i = 0;
for (i = 0; i < size; i++){
printf("name : %s\t age : %d\n", arr->name, arr->age);
arr++;
}
}
/*
*/
int main(){
struct People arr[] = { { "zhangsan", 20 }, { "lisi", 12 }, { "wanger", 22 }, {"mazi",16} };
//数组大小
int size = sizeof(arr) / sizeof(arr[0]);
//手写万能冒泡排序:
MyQSort(arr, size, sizeof(arr[0]), Mycmp_age);
//打印
Printfs(arr, size);
return 0;
}