当你为错过太阳而哭泣的时候,你也要再错过群星了。 --泰戈尔
目录
一.qsort快速排序的实现
二.模拟实现一个qsort功能的函数
一.qsort快速排序的实现
下面是 qsort() 函数的声明:
void qsort(void *base, size_t nitems, size_t size, int (*compare)(const void *p1, const void* p2))
注意:p1和p2是待比较两个数的地址,你不能直接写成*p1和*p2来找到这两个数,因为p1和p2都是void*的指针,无类型的指针。void*可以接收任何类型的指针,所以使用*p1和*p2时,你必须强制类型转换为你需要的类型。
参数:
- base -- 指向要排序的数组的第一个元素的指针。
- nitems -- 由 base 指向的数组中元素的个数。
- size -- 数组中每个元素的大小,以字节为单位。
- compare -- 用来比较两个元素的函数,其实就是一个函数指针。
对一个数组里面的数字进行升序排序,可以使用冒泡排序(之前写的) ,但是冒泡排序效率比较低,而且只能对数字进行排序,但是qsort函数可以实现各种各样的排序。
我们就先来使用qsort来对数组的数字进行升序排序。
#include<stdio.h>
#include<stdlib.h>//qsort所需要的头文件
int cmp_int(const void* p1, const void* p2)
//cmp_int这个函数是我们使用者提供的,你可以随便写成什么名字
{
return (*(int*)p1 - *(int*)p2);//(int*)强制类型转换为整型指针,再解引用找到元素
}
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 5,3,7,8,9,1,2,0,4,6 };
//void qsort(void* base, size_t nitems, size_t size, int (*compare)(const void* p1, const void* p2))
int sz = sizeof(arr) / sizeof(arr[0]);//求的数组的大小,对应的就是nitems
//这里的arr对应base
//sizeof(arr[0])对应的就是size,数组每个元素的字节大小
qsort(arr, sz, sizeof(arr[0]), cmp_int);
print(arr, sz);
return 0;
}
我们再来使用qsort来实现复杂一点点的结构体名字排序,你就会感到qsort的神奇之处。
我们对一个字符串进行比较,自然要用到strcmp函数。
strcmp函数:用于比较两个字符串的ASCll值并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数,strcmp函数是对字符串一个一个字符进行比较,如果第一个字符串的第一个字符已经大于第二个字符串的第一个字符了,strcmp就直接返回0了,就不用继续比较下面的字符串了。
比如:abcdf和fbb字符串进行比较,因为a的ASCll值已经小于f的ASCll值了,所以返回小于0。比较结束。
#include<stdio.h>
#include<stdlib.h>
struct stu
{
int age;
char name[20];
};
int cmp_name(const void* p1, const void* p2)
{
return strcmp(((struct stu*)p1)->name, ((struct stu*)p2)->name);
//指针访问结构体变量使用->
}
void print(struct stu S[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s\n", S[i].name);
}
}
int main()
{
struct stu S[] = { {20,"chen kang"},{19,"wang ti"},{21,"di shu"} };
//创建一个结构体数组
int sz = sizeof(S) / sizeof(S[0]);
qsort(S, sz, sizeof(S[0]), cmp_name);
print(S, sz);
return 0;
}
上面我们使用qsort函数来排序数组和结构体中的字符串,可以看出qsort不用像冒泡排序那样确定趟数,而是qsort自己继续往后面排序。
总结qsort函数优点:
1.不需要确定趟数。
2.可以对各种类型进行排序。
二.模拟实现一个qsort功能的函数
接下来我们就要来写一个模拟qsort函数功能的函数,来理解qsort函数到底是如何进行排序的。
#include<stdio.h>
void Swap(char* p1, char* p2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{ //width就是一个数的字节大小
char temp = 0;
temp = *p1;
*p1 = *p2;
*p2 = temp;
p1++;
p2++;
//通过一个一个的字节交换,从而将一个数交换
}
}
void sml_qsort(void* base, size_t num, size_t width, int(*cmp)(const void* p1, const void* p2))
{
//size_t表=表示无符号整型,这里也可以写成int
int i = 0;
int j = 0;
for (i = 0; i < num - 1; i++)
{
for (j = 0; j < num - 1 - i; j++)
{
if (cmp((char*)base + j * width ,(char*)base + (j + 1) * width) > 0)
{
//(char*)base + j * width就是一个数的全部字节大小,无论是排序什么类型,都可以这样使用
//这里调用cmp指针从而调用cmp_int函数,而cmp_int就是比较两个数的大小
//cmp就是一个回调函数
Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
}
}
}
}
int cmp_int(const void* p1, const void* p2)
{
return *(int*)p1 - *(int*)p2;
}
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 1,4,7,3,2,5,8,0,9,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
sml_qsort(arr, sz, sizeof(arr[0]),cmp_int);
//sml是simulation单词的缩写,也就是模拟的意思
print(arr, sz);
return 0;
}
我们还可以用sml_sqort函数来排序结构体等等,只需要修改一点点代码就可以实现。这里大家就可以自己动手尝试。
希望大家给老弟赞赞,谢谢!