qsort 函数是一个在 C 标准库 - <stdlib.h> 下的一个函数,下面便是qsort库函数的实现过程。(并不是标准库里的定义,只是帮助理解)
我们知道qsort函数使用时会需要四个值
例如: qsort ( arr, sizeof(arr)/sizeof(arr[0]) , sizeof(arr) , 自己的运算函数)
1:数组首地址。
2:数组元素个数。
3:单个元素所占用的字节数。
4:自己所定义的运算法则。(我们知道qsort是任意类型数组的排序,我们肯定是知道需要排序数组的类型的,这时我们需要“告诉”qsort函数我们所对比元素的类型)
以下是对qsort函数的理解实现:
-------------------------------------------------------------------------------------------------------------------------------
#include <string.h>
void swap(char* arr1,char*arr2,int length)
{
int i;
for (i = 0; i < length; i++)
{
char tmp = *(arr1 + i);
*(arr1+i) = *(arr2 + i);
*(arr2 + i) = tmp;
}
}
void my_qsort(void* arr, int sz, int length, int (*contrast)(void* x,void* y)) //第四个元素之所以是 int 类型 是因为这个指针所指向的函数是返回的是int类型的数值。
{
int i, j;
for (i = 0; i < sz; i++)
{
for (j = 0; j < sz-1-i; j++)
{
if (contrast((char*)arr + j*length, (char*)arr + (j+1)*length) > 0) //contrast是个函数,函数地址可以直接当作函数名来用,函数名的本质其实就是函数地址。
{
swap((char*)arr + j*length, (char*)arr + (j+1)*length,length);
}
}
}
}
int contrast_int(void* x, void* y)
{
return *(int*)x - *(int*)y;
}
int main()
{
int arr[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
my_qsort(arr, sz, sizeof(arr[0]), contrast_int);
return 0;
}
以上是对int元素类型的函数进行实现,但我们知道,qsort函数是对任意类型,实现函数自然也可以做到。下面便是结构体中的字符串排序。
#include <string.h>
struct bbb
{
char name[20];
int age;
};
void swap(char* arr1,char*arr2,int length)
{
int i;
for (i = 0; i < length; i++)
{
char tmp = *(arr1 + i);
*(arr1+i) = *(arr2 + i);
*(arr2 + i) = tmp;
}
}
void my_qsort(void* arr, int sz, int length, int (*contrast)(void* x,void* y)) //第四个元素之所以是 int 类型 是因为这个指针所指向的函数是返回的是int类型的数值。
{
int i, j;
for (i = 0; i < sz; i++)
{
for (j = 0; j < sz-1-i; j++)
{
if (contrast((char*)arr + j*length, (char*)arr + (j+1)*length) > 0) //contrast是个函数,函数地址可以直接当作函数名来用,函数名的本质其实就是函数地址。
{
swap((char*)arr + j*length, (char*)arr + (j+1)*length,length);
}
}
}
}
int contrast_str(const void* x,const void* y)
{
return strcmp(((struct bbb*)x)->name, ((struct bbb*)y)->name);
}
int main()
{
struct bbb ppp[3] = { { "cc", 10 }, { "bb", 20 }, { "aa", 30 } };
int szppp = sizeof(ppp) / sizeof(ppp[0]);
my_qsort(ppp, szppp, sizeof(ppp[0]), contrast_str);
return 0;
}
为了方便理解,这次通过第一个对整型类型的数组排序进行解释。
int main()
{
int arr[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
my_qsort(arr, sz, sizeof(arr[0]), contrast_int);//这是我们对qsort函数的实现。我们可以看到有一个contrast_int,这便是我们要输入的对比 法则
return 0;
}
void my_qsort(void* arr, int sz, int length, int (*contrast)(void* x,void* y))
//为什么是void类型?因为void*的指针可以包含所有类型的地址。
//第四个元素之所以是 int 类型 是因为这个指针所指向的函数是返回的是int类型的数值。
{
int i, j;
for (i = 0; i < sz; i++)
{
for (j = 0; j < sz-1-i; j++)
{
if (contrast((char*)arr + j*length, (char*)arr + (j+1)*length) > 0)//contrast是个函数,函数地址可以直接当作函数名来用,函数名的本质其实就是函数地址。
//为什么要强制转化成char*类型的?
// char* 搭配 length(单个元素所占用的字节数)可以做到跳元素。
//例如int* 、char*等指针类型,它的含义并不单单只是存储地址那么肤浅,更重要的是解引用或者自增自减时,可以做到跳字节,比如int可以跳四个字节,char可以跳一个字节。
{
swap((char*)arr + j*length, (char*)arr + (j+1)*length,length);
}
}
}
}
void swap(char* arr1,char*arr2,int length)
//替换函数,通过char*和length实现两元素间的替换
{
int i;
for (i = 0; i < length; i++)
{
char tmp = *(arr1 + i);
*(arr1+i) = *(arr2 + i);
*(arr2 + i) = tmp;
}
}
以下是上述代码所呈现的效果: