C语言 qsort函数及其实现
part 1.认识qsort()函数
qsort()库函数原型如下:
/*void* base----指向待排序数据的起始位置的一个指针
size_t size---- 由base指向的数组中元素的个数。
size_t width----数组中每个元素的大小,以字节为单位
int(__cdecl *compare )(const void *elem1, const void *elem2 )----用来比较两个元素的函数,即函数指针(函数回调)
*/
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
如果想要升序(降序)代码示例如下:
此函数是专门比较(int)的,如需比较其他型,请把此处的(int*)更改。
int cmp_int(const void* e1, const void* e2)
{
//升序
//return (*(int *)e1 - *(int*)e2);
//降序
return (*(int*)e2 - *(int*)e1);
}
part 2.简单运用qsort()函数
下面我们先运用qsort()函数排序一个一维数组。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//打印数组函数
//int* arr---整形指针指向数组
//int sz --存储数组的大小
void print(int* arr, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
/*如果compar返回值小于0(< 0),那么e1所指向元素会被排在e2所指向元素的左面;
如果compar返回值等于0(= 0),那么e1所指向元素与e2所指向元素的顺序不确定;
如果compar返回值大于0(> 0),那么e1所指向元素会被排在e2所指向元素的右面。*/
int cmp_int(const void* e1, const void* e2)
{
//升序
//return (*(int *)e1 - *(int*)e2);
//降序
return (*(int*)e2 - *(int*)e1);
}
void test1()
{
//运用qsort 排序一个整形数组
int arr[] = {
9,0,5,7,6,1,3,2,8 ,4 };
int sz = sizeof(arr) / sizeof(arr[0]);
//需要引头文件---- #include<stdlib.h>
qsort(arr, sz, sizeof(arr[0]), cmp_int);
print(arr, sz);
}
int main()
{
test1();
return 0;
}
既然能排序数组,那能不能排序结构体呢?
答案是:能。具体示例如下代码:
struct stu
{
char m_name[20]; //姓名
int age; //年龄
};
/*如果compar返回值小于0(< 0),那么e1所指向元素会被排在e2所指向元素的左面;
如果compar返回值等于0(= 0),那么e1所指向元素与e2所指向元素的顺序不确定;
如果compar返回值大于0(> 0),那么e1所指向元素会被排在e2所指向元素的右面。*/
int cmp_age(const void* e1, const void* e2)
{
//按年龄升序
return (*(stu*)e1).age - (*(stu*)e2).age;
//按年龄降序
//return (*(stu*)e2).age - (*(stu*)e1).age;
}
int cmp_name(const void* e1, const void* e2)
{
//按名字升序
//当然字符串不能像之前那样直接比较
//而应该使用库函数strcmp()来比较大小
/*strcmp()函数原型
int strcmp( const char *string1, const char *string2 );
当s1<s2时,返回为负数;
当s1=s2时,返回值= 0;
当s1>s2时,返回正数
*/
return strcmp((*(stu*)e1).m_name,(*(stu*)e2).m_name);
//按名字降序
//return strcmp((*(stu*)e2).m_name,(*(stu*)e1).m_name);
}
void test2()
{
//使用qsort函数排序结构体
stu arr[] = {
{
"zhansan",20},{
"lisi",30},{
"wangwu",10} };
int sz=sizeof(arr) / sizeof(arr[0]);
//按年龄排序
qsort(arr, sz, sizeof(arr[0]), cmp_age); //-----qsort的第四个参数是函数指针
//按名字排序
qsort(arr, sz, sizeof(arr[0]), cmp_name);
}
int main()
{
test2();
return 0;
}
part 3.用冒泡排序模拟实现库函数qsort()
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void _swap(char* buf1, char* buf2,size_t width)
{
int i = 0;
for (i = 0; i < width; i++)
{
//一个字节一个字节的交换
char temp = *buf1;
*buf1 = *buf2;
*buf2 = temp;
buf1++;
buf2++;
}
}
void bubble_sort(void* base, size_t size, size_t width, int (*cmp)(const void* e1, const void* e2))
{
size_t i = 0;
for (i = 0; i < size - 1; i++)
{
size_t j = 0;
//判断是否排好序的一个标志
/*如果flag==true则证明这趟还没排好序,如果flag==false,则排好序,之后的趟数可以
不用进行了*/
bool flag = false;
for (j = 0; j < size - 1 - i; j++)
{
//相邻俩个元素的比较
//(char*)的强制类型转换为了实现一个字节一个字节的加减,方便找到之后元素
//+j*width可以找到第j号元素的首地址,依次类推
//就像冒泡排序一样if(arr[j]>arr[j+1])就交换
if (cmp((char *)base+j*width,(char *)base+(j+1)*width)>0)
{
//如果不满足顺序就交换
_swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
flag = true;
}
}
if (false == flag)
{
break;
}
}
}
struct stu
{
char m_name[20]; //名字
int age; //年龄
};
int cmp_age(const void* e1, const void* e2)
{
//按年龄升序
return (*(stu*)e1).age - (*(stu*)e2).age;
//按年龄降序
//return (*(stu*)e2).age - (*(stu*)e1).age;
}
int cmp_name(const void* e1, const void* e2)
{
//按名字升序
return strcmp((*(stu*)e1).m_name, (*(stu*)e2).m_name);
//按名字降序
//return strcmp((*(stu*)e2).m_name,(*(stu*)e1).m_name);
}
void test3()
{
stu arr[] = {
{
"zhansan",10},{
"lisi",20},{
"wangwu",30} };
int sz = sizeof(arr) / sizeof(arr[0]);
//按年龄排序
bubble_sort(arr, sz, sizeof(arr[0]), cmp_age);
//按名字排序
//bubble_sort(arr, sz, sizeof(arr[0]), cmp_name);
}
int main()
{
test3();
}