C语言:qsort 库函数实现(任意类型数组排序)[实现+理解]

发布于:2022-10-19 ⋅ 阅读:(549) ⋅ 点赞:(0)

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;
    }
}

以下是上述代码所呈现的效果:

 

 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到