文章目录
#1.复习冒泡排序
#2. 讲解qsort函数
#3. 用冒泡排序来模拟qsort函数
参考这篇文章: 写文章-CSDN创作中心
先说一下原始冒泡排序的问题,如果一个数组是排好序的,那么这个冒泡函数还是会进行一趟一趟的冒泡排序,一次一次的比较,代码效率过于低,将代码改成如下的形式, 升级版的冒泡排序 :
void bubble_sort(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int flag = 1; //假设数组是排好序的
int j = 0;
for (j = 0; j < sz - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;
}
}
if (flag == 1) //数组确实是有序的,不用进行下一趟的排序,排序效率提高
{
break;
}
}
}
int main()
{
//int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
定义一个flag变量,如果一趟冒泡排序下来一对元素都没有进行交换,那么就说明这个数组是排好序的,就不会进行下一趟的冒泡排序直接跳出循环,代码效率提高
是C语言中的一个排序函数,可以对任意的数据类型进行排序,默认排序成升序
如果比较2个整型元素,elem1指向一个整数 elem2指向另一个整数
qsort函数的用法,代码演示如下:
#include
#include
int cmp_int(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}; //排成升序
//0 1 2 3 4 5 6 7 8 9
//把数组排成升序
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
qsort(arr, sz, sizeof(arr[0]), cmp_int);
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
自己提供一个cmp_int函数,根据qsort的返回值,只需将cmp_int函数的返回值设置成一个元素减一个元素即可,即元素1>元素2,返回>0;即元素1<元素2,返回<0;即元素1=元素2,返回=0;
这里需要注意的是编写的cmp_int函数的参数是void*类型,void*是无具体类型的指针,可以接受任意类型的地址,不能解引用操作, 也不能+-整数,所以对其解引用时需要强制类型转换成int*类型
还可以对结构体中的成员变量进行排序,代码演示如下:
#include
#include
#include
struct Stu
{
char name[20];
int age;
};
int cmp_stu_by_name(const void* e1, const void* e2)
{
//strcmp --> >0 ==0 <0
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int cmp_stu_by_age(const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
void test2()
{
//测试使用qsort来排序结构体数据
struct Stu s[] = { {"zhangsan", 15}, {"lisi", 30}, {"wangwu", 25} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}
int main()
{
test2();
return 0;
}
当然同样需要将void*指针强制类型转换成(struct Stu*)的类型,注意在比较字符串长度的时候不能直接比较需要用strcmp函数比较
总结:使用qsort函数时需要自己提供一个比较函数来进行比较
1.首先来学习qsort函数的参数是如何编写的,模仿qsort函数的参数来编写冒泡函数的参数
2.其次整个冒泡排序的大框架不用改变,只是一对一对元素进行比较时要修改,在比较元素是我们是不知道这个元素的数据类型的(也就是不知道这个元素是几个字节的),那么怎么找到一个元素呢 ,就需要强制类型转换成char*类型的,然后去乘以宽度就能找到这一个元素,因为char是一个字节比较方便
3.如果第一个元素大于第二个元素就会进入if语句后交给Swap函数来进行元素的交换,Swap函数交换的时候因为已经将void*指针强制类型转换成char*了,就直接用char*的指针来接收,交换的时候,需要创建临时变量在宽度的范围内进行一个字节一个字节的交换
以一个整型数组为例,代码如下:
#include
#include
int cmp_int(const void*e1, const void*e2)
{
return(*(int*)e1-*(int*)e2);
}
void Swap(char*buff1, char*buff2, int width)
{
int i=0;
for(i=0;i0)
{
Swap((char*)base+j*width,(char*)base+(j+1)*width, width);
flag=0;
}
}
if (flag == 1) //数组确实是有序的,不用进行下一趟的排序,排序效率提高
{
break;
}
}
}
void test3()
{
int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz,sizeof(arr[0]), cmp_int);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
test3();
return 0;
}
结构体成员排序的代码如下:
#include
#include
struct Stu
{
char name[20];
int age;
};
int cmp_stu_by_name(const void* e1, const void* e2)
{
//strcmp --> >0 ==0 <0
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int cmp_stu_by_age(const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
void Swap(char* buff1, char* buff2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *buff1;
*buff1 = *buff2;
*buff2 = tmp;
buff1++;
buff2++;
}
}
void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int flag = 1; //假设数组是排好序的
int j = 0;
for (j = 0; j < sz - i - 1; j++)
{
if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
{
Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
flag = 0;
}
}
if (flag == 1)
{
break;
}
}
}
void test4()
{
struct Stu s[] = { {"zhangsan", 15}, {"lisi", 30}, {"wangwu", 25} };
int sz = sizeof(s) / sizeof(s[0]);
bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_name);
bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}
int main()
{
test4();
return 0;
}
总结:冒泡排序模拟qsort函数时,整体的大框架比较、交换都是相同的,就是在比较函数cmp上写法上有些不同