qsort:“快排”的模拟实现
```c
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#pragma warning(disable:4996)
typedef struct Student//定义结构体
{
int id;
char name[10];
int age;
char sex[3];
}Student;
int my_intcompare(const void *s1, const void *s2)//整形比较大小
{
return *(int*)s1 - *(int*)s2;
}
int my_charcompare(const void *s1, const void *s2)//字符比较大小
{
return *((char*)s1) - *((char*)s2);
}
int my_strcompare(const void *elem1, const void *elem2)//字符串比较大小
{
return strcmp(*((char**)elem1), *((char**)elem2));
}
int my_structcompare(const void *elem1, const void *elem2)//结构体根据年龄比较大小
{
Student *s1 = (Student*)elem1;
Student *s2 = (Student*)elem2;
return s1->age - s2->age;
}
int my_floatcompare(const void *elem1, const void *elem2)//单精度类型数据比较大小
{
const float* s1 = elem1;
const float* s2 = elem2;
if (*s1 > *s2)
return 1;
else if (*s1 == *s2)
return 0;
return -1;
}
int my_doublecompare(const void *elem1, const void *elem2)//双精度类型数据比较大小
{
const double* s1 = elem1;
const double* s2 = elem2;
if (*s1 > *s2)
return 1;
else if (*s1 == *s2)
return 0;
return -1;
}
void my_qsort(void *base, size_t n, size_t width, int(*compare)(s1,s2))
{
assert(base!=NULL);
void *tmp = malloc(width);//为了提高效率,尽量减少空间的多次重复申请和被重复释放,所以将定义tmp的工作放到了for循环的外边
for (int i = 0; i < n - 1; i++)//冒泡排序
{
for (int j = 0; j < n - 1 - i;j++)
{
if (compare(((char*)base + j*width), ((char*)base + (j + 1)*width))>0)//此处的compare实际为:int (*compare)(const void*,const void*),通过函数指针来调用相应的函数
{//这里通过使用memcpy来实现数据的交换
memcpy(tmp, ((char*)base + j*width), width);
memcpy(((char*)base + j*width), ((char*)base + (j + 1)*width),width);
memcpy(((char*)base + (j + 1)*width),tmp, width);
}
}
}
free(tmp);
}
void Print_Array(int *s, int left, int right)//打印整型数组
{
assert(s != NULL);
while (left < right)
{
printf("%d ", s[left]);
left++;
}
printf("\n");
}
void Print_Array1(char *s, int left, int right)//打印字符数组
{
assert(s != NULL);
for (int i = left; i < right; i++)
{
printf("%c ", s[i]);
}
printf("\n");
}
void Print_Array2(char *s[], int left, int right)//打印字符串
{
assert(s != NULL);
for (int i = left; i < right; i++)
{
printf("%s ", s[i]);
}
printf("\n");
}
void Print_Array3(Student stu[], int left, int right)//打印结构体数组
{
assert(stu != NULL);
for (int i = left; i < right;i++)
{
printf("%d %s %d %s\n", stu[i].id,stu[i].name,stu[i].age,stu[i].sex);
}
printf("\n");
}
void Print_Array4(float* s, int left, int right)//打印单精度数组
{
assert(s != NULL);
for (int i = left; i < right; i++)
{
printf("%f ", s[i]);
}
printf("\n");
}
void Print_Array5(double* s, int left, int right)//打印双精度数组
{
assert(s != NULL);
for (int i = left; i < right; i++)
{
printf("%f ", s[i]);
}
printf("\n");
}
int main()
{
int ar[] = {32, 95, 55, 52 };
char br[] = { 'a', 'g', 'h', 'y', 'm' };
char* cr[] = { { "likethis" }, {"missyou"},{ "thedown" }};
Student stu[] = { { 555, "张三", 21, "男" }, { 666, "李四", 19, "男" }, {777,"二狗",20,"男"} };
float dr[] = { 0.5f, 0.4f, 0.8f, 0.2f };
double er[] = { 7.8, 12, 6.3, 5.2 };
int n = sizeof(ar) / sizeof(ar[0]);
int n1 = sizeof(br) / sizeof(br[0]);
int n2 = sizeof(cr) / sizeof(cr[0]);
int n3 = sizeof(stu) / sizeof(stu[0]);
int n4 = sizeof(dr) / sizeof(dr[0]);
int n5 = sizeof(er) / sizeof(er[0]);
Print_Array(ar, 0, n);
my_qsort(ar, n, sizeof(int), my_intcompare);
Print_Array(ar, 0, n);
Print_Array1(br, 0, n1);
my_qsort(br, n1, sizeof(char), my_charcompare);
Print_Array1(br, 0, n1);
Print_Array2(cr, 0, n2);
my_qsort(cr, n2, sizeof(char*), my_strcompare);
Print_Array2(cr, 0, n2);
Print_Array3(stu, 0, n3);
my_qsort(stu, n3, sizeof(Student), my_structcompare);
Print_Array3(stu, 0, n3);
Print_Array4(dr, 0, n4);
my_qsort(dr, n4, sizeof(float), my_floatcompare);
Print_Array4(dr, 0, n4);
Print_Array5(er, 0, n5);
my_qsort(er, n4, sizeof(double), my_doublecompare);
Print_Array5(er, 0, n5);
system("pause");
return 0;
}
模拟qsort的实现要求:1.对冒泡排序的掌握。2. 要能理解void* 空类型指针的含义和他的灵活用法3. 对函数指针的彻底了解能够使函数指针来灵活的使代码的冗余性降低很多,同时也会提高代码的执行效率。