c语言(qsort函数的应用及其模拟实现)

1.冒泡排序

前面我们学习过冒泡排序

现在来回顾一下

#include <stdio.h>
void bubble_sort(int arr[], int sz);
void arr_printf(int arr[], int sz);
int main()
{
	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);
	arr_printf(arr, sz);
	return 0;
}
void bubble_sort(int arr[],int sz)
{
	for (int i = 0; i < sz - 1; i++)
	{
		for (int j = 0; j < sz - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp;
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}

}
void arr_printf(int arr[], int sz)
{
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

冒泡排序通过比较两个整数的大小,若前一个数比后一个数大,就交换这两个数,通过多次循环最后达到升序排列的效果。

但是冒泡排序具有局限性,他只能排列整型的顺序。

那如何实现对任意类型进行排序呢?

C语言提供了一个库函数qsort函数,它可以实现对任意类型进行排序。

2、qsort函数

void qsort (void* base, size_t num, size_t size,
            int (*compar)(const void*,const void*));

我们来看一下他的四个参数,无返回值。

第一个参数是一个指针变量,它存放的的是数组首元素的地址。

第二个参数是数组中元素的个数。

第三个参数是每个元素的大小,单位是字节。

第四个参数是一个函数指针。指针指向一个函数,该函数用于比较两个元素的大小。

使用时需要自己定义一个比较函数。我们举个例子。

#include <stdio.h>
#include <stdlib.h>    //使用qsort函数要包含头文件
int compar(const void* e1, const void* e2);
void arr_printf(int arr[], int sz);
int main()
{
	int arr[10] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
	qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), compar);
	arr_printf(arr, sizeof(arr) / sizeof(arr[0]));
	return 0;
}

int compar(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;   //若前一个元素比后一个元素大,返回大于0的数
                                    //若前一个元素比后一个元素小,返回小于0的数
                                    //若前一个元素与后一个元素相等,则返回0
}
void arr_printf(int arr[], int sz)
{
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

 

 3、用冒泡函数模拟实现qsort函数

既然是模拟那函数也应该是这四个参数

void bubble_sort(void* base, int num, int size,
	int (*compar)(const void*, const void*));

原冒泡排序程序: 

for (int i = 0; i < sz - 1; i++)
	{
		for (int j = 0; j < sz - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp;
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}

用冒泡排序模拟,那冒泡函数的思想是不需要变的,只需要把if语句里的比较大小变成一个比较函数,为什么要变成函数呢?因为用户想进行排序的不一定是整形数组,还有可能是浮点型,短整型,结构体等多种数据类型(类似上一篇文章的回调函数思想),所以我们要调用一个函数,把不同数据类型数组中相邻元素的地址当参数传过来,若前一个元素比后一个元素大,返回大于0的数,若前一个元素比后一个元素小,返回小于0的数 ,若前一个元素与后一个元素相等,则返回0。代码如下

void bubble_sort(void* base, size_t num, size_t size,int (*compar)(const void*, const void*))
{
	for (int i = 0; i < num - 1; i++)
	{
		for (int j = 0; j < num - i - 1; j++)
		{
			if (compare( (char*)base+size*j, (char*)base + size * (j+1) )> 0)
			{
				//交换数据
				swap();
				return
			}
		}
	}

}

如果函数返回值大于0,则说明前一个元素比后一个元素大,我们想要得到升序的排列,那就应该交换,所以还应该写一个用于交换数据的函数。

void swap(char* a1 , char* a2, int size) //因为不知道具体类型,所以要一个字节一个字节的交换
{
	for (int i = 0; i < size; i++)
	{
		char tmp;
		tmp = *a1;
		*a1 = *a2;
		*a2 = tmp;
		a1++;
		a2++;
	}
}

完整代码

 

#include <stdio.h>
void bubble_sort(void* base, size_t num, size_t size, int (*compar)(const void*, const void*));
void swap(char* a1, char* a2, int size);
int compare(const void* e1, const void* e2);
void arr_printf(int arr[], int sz);
int main()
{
	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sizeof(arr)/sizeof(arr[0]), sizeof(int), compare);
	arr_printf(arr, sz);
	return 0;
}
void bubble_sort(void* base, int num, int size,int (*compar)( void*,  void*))
{
	for (int i = 0; i < num - 1; i++)
	{
		for (int j = 0; j < num - i - 1; j++)
		{
			if (compare( (char*)base+size*j, (char*)base + size * (j+1) )> 0)
			{
				//交换数据
				swap((char*)base + size * j, (char*)base + size * (j + 1), size);
	
			}
		}
	}

}
void swap(char* a1 , char* a2, int size)
{
	for (int i = 0; i < size; i++)
	{
		char tmp;
		tmp = *a1;
		*a1 = *a2;
		*a2 = tmp;
		a1++;
		a2++;
	}
}
int compare(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
void arr_printf(int arr[], int sz)
{
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

运行结果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值