一、冒泡排序的局限性
说到排序,我们首先可能会想到冒泡排序,它非常的方便。但是,他也有他的局限性,因为对于一个特定的冒泡排序,一般只能排序一种类型的数据
比如下面
#include <stdio.h>
void bubble_sort(int arr[],int sz)
{
int i = 0;
for (i = 0; i < sz-1 ; i++)
{
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;
}
}
}
}
int main()
{
int arr[] = { 0,2,4,6 ,3,1,7,5,8,9};
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr,sz);
int i = 0;
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
对于这一个冒泡排序,我们只能对整形数组进行排序,对于其他数组就无能为力了。那么怎么写出一个万能的函数,可以排序所有类型的的数组呢?其实C语言库里面就有了这个函数,他就是qsort那么让我们了解一下它的底层逻辑。
二 代码展示
为了方便展示,我们依旧采用整形数组
#include<stdio.h>
int com_int(void* e1, void* e2);
int main()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), com_int);
int i;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
int com_int(void* e1, void* e2)
{
return *(int*)e1 - *(int*)e2;
}
在这段代码中,我们用了qsort这一个函数,可以观察到,这个函数有四个参数,分别为,arr, sz, sizeof(arr[0]), com_int。
其中,arr是数组名,也是数组首元素地址。sz是数组的元素个数。sizeof(arr[0])是数组内元素的大小,com_int是我们自己写的函数,它的作用就是比较两个元素的大小。所以,当我们用的时候只需要写com_int这个函数就可以了。
三my_qsorth函数的实现。
我们先看最后一个函数。再看倒数第二个,第一个。
int com_int(void* e1, void* e2)
{
return *(int*)e1 - *(int*)e2;
//(int*)e1 的作用是直接与返回值对应,都为整形,再进行加减;
}
void swap(char* e1, char* e2,int width)
{
int i;
for (i = 0; i < width; i++)
//char*一次只能交换一个字节,所以进行width次
{
char tmp = *e1;
*e1 = *e2;
*e2 = tmp;
e1++; e2++;
}
}
void my_qsort(void*arr,int sz,int width,int* com(void* e1,void* e2))
{
//void*arr,是给出数组的首元素地址,因为不知道要排序什么类型的数据,所以用空指针。
//sz是数组中元素的个数
//width是数组元素所占的字节数
//int* com(void* e1,void* e2)是一个函数指针,用来比较大小,这个函数需要我们自己完成。
int i, j;
for (i = 0; i < sz - 1; i++)
{
for (j = 0; j < sz - i - 1; j++)//冒泡排序的原理,还是两次循环,我们需要变得只有比较方法。
{
if (com((char*)arr+j*width, (char*)arr+(j + 1)*width)>0)
//当这个函数的返回值大于零时,就是第一个元素比第二个元素大
//因为void*不可以加减运算所以需要强制类型转换为其他类型
//转换成char*的原因是因为char*一次只访问一个字节,我们再加上width,就是一次访问数据 类型所对应的字节
//j*width代表了比较的数据,每次不一样,随着循环递增
{
swap((char*)arr + j * width, (char*)arr + (j + 1) * width, width);
//交换的函数
}
}
}
}
以上就是qsort的底层逻辑