C语言 模拟实现qsort函数(冒泡排序)

冒泡排序

#include <stdio.h>
void bubble_sort(int*, int);
int main()
{
    int arr[5] = { 99, 45, 78, 55, 23 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    bubble_sort(arr, sz);
    int i = 0;
    for (i = 0; i < sz; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}
void bubble_sort(int* arr, int n)
{
    int i = 0;
    for(i = 0; i < n - 1; i++)
    {
        int j = 0;
        for (j = 0; j < n - 1 - i; j++)
        {
            if (arr[j] > arr[j + 1])
            {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

在bubble_sort函数中,n代表数组的长度,外层的循环变量是 i ,代表遍历数组的次数,在数组长度为 n 的情况下,会遍历 n-1 次,i 从 0 开始,i 的取值范围是 [0, n-1)。内层循环变量是 j ,因为每次循环都可以把最后一个元素的值确定,所以 j 的值在每次遍历完一遍数组后都会减 1 ,也就是说 j 的取值与 i 的取值相关, i 的取值是[0, n - 1), 所以 j 的取值是[0, n - 1 - i),每次对 arr[ j ] 和 arr[ j + 1 ]进行比较,满足条件的进行交换。
在这个冒泡排序中,我们只能对 int 类型的数组进行排序,而不能对其它类型的元素进行排序。

qsort函数

void qsort( void *base, size_t num, size_t width, int (*compare )(const void *elem1, const void *elem2 ) );
如果要使用qsort函数,需要引用头文件<stdlib.h>,qsort函数可以对任意类型的数据进行排序,但qsort函数在使用时需要自定义一个函数compare,通过该函数的返回值来确定是否进行交换,和上面冒泡排序中的判断 arr[ j ] 和 arr[ j + 1 ] 的大小来决定是否交换类似。
对qsort函数感兴趣的可以点击这个链接: qsort函数

模拟实现

如果想要通过冒泡排序来进行对任意元素的排序,就需要像qsort函数那样,假设对需要排序的数组一无所知,我们需要获取该数组的起始地址,起始地址的类型设置成void*, 我们还需要获取数组的元素个数,该参数可以设置成 int (个数不会为负数,可以选择unsigned int,也就是qsort函数的size_t ),还需要知道每个元素的大小,才能知道下一个元素的起始地址,可以设置成 int 类型,此外,我们还需要一个compare函数,这个函数由用户自己设计,该函数的返回值应该为 int 类型,如果返回值大于0,进行相邻两个元素的交换,该函数的两个参数应该是数组中两个相邻元素的起始地址。

bubble_sort函数

对刚才的冒泡排序函数进行修改,就可以得到可以交换任何数据的冒泡排序函数。通过给出的数据,可以计算出相邻的两个元素的起始地址分别是,arr + width * j 和 arr + width * (j + 1) ,将两个元素的起始地址传到compare函数中进行数据的计算,通过返回值判断是否对这两个元素进行交换。

void bubble_qsort(const void* arr, int num, int width, int(*p)(void*, void*))
{
	int i = 0;
	int j = 0;
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - 1 - i; j++)
		{
			if (p((char*)arr + width * j, (char*)arr + width * (j + 1)) > 0)
			{
				swap((char*)arr + width * j, (char*)arr + width * (j + 1), width);
			}
		}
	}
}

swap函数

因为char类型只占一个字节,所以可以将传来的两个地址强制类型转换为char*,因为要对两个元素进行交换,所以要交换所有字节,还需要知道每个元素占的字节数,所以还需要传个 int 类型的变量来保存字节数。

void swap(char* n1, char* n2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char temp = *(n1 + i);
		*(n1 + i) = *(n2 + i);
		*(n2 + i) = temp;
	}
}

compare函数

compare函数是用户自定义的函数,用户是知道数据的类型的,所以可以先将数据进行相应的类型转换,然后对转换后的数据进行计算,如果第一个元素大于第二个,返回值为正;如果第一个元素小于第二个元素,返回值为负。
因为返回值是int类型的,所以对于int类型的变量,可以返回两个变量相减的结果;对于double类型,需要对两个变量的大小进行比较;对于字符串类型,可以直接使用strcmp()作为返回值。

int int_cmp(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
int cmp_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int cmp_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int cmp_double(const void* e1, const void* e2)
{
    return *(double*)e1 > *(double*)e2 ? 1 : 0;
}

代码示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int int_cmp(const void*, const void*);
int cmp_age(const void*, const void*);
int cmp_name(const void*, const void*);
int cmp_double(const void*, const void*);
void bubble_qsort(const void*, int, int, int(*)(void*, void*));
void swap(char*, char*, int);
struct Stu
{
	int age;
	char name[4];
};
int main()
{
	int arr[10] = { 2, 4, 1, 9, 7, 8, 6, 5, 10, 3 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
    double arr1[10] = {2.4, 9.8, 5.6, 8.7, 3.3, 99.4, 56.4, 21.9, 42.5, 15.6};
    int len = sizeof(arr1) / sizeof(arr1[0]);
    bubble_qsort(arr1, len, sizeof(arr1[0]), cmp_double);

	bubble_qsort(arr, sz, sizeof arr[0], int_cmp);

	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
    putchar('\n');
    for (i = 0; i < len; i++)
	{
		printf("%.1f ", arr1[i]);
	}
    printf("\n");

	struct Stu s1 = { 20, "Tom" };
	struct Stu s2 = { 115, "Ac" };
	struct Stu s3 = { 99, "Ji" };
	struct Stu s[3] = { s1, s2, s3 };

	int num = sizeof(s) / sizeof(s[0]);
	bubble_qsort(s, num, sizeof(s[0]), cmp_age);
    for (i = 0; i < num; i++)
    {
        printf("%d ", s[i].age);
    }
    printf("\n");
    
	bubble_qsort(s, num, sizeof(s[0]), cmp_name);
    for (i = 0; i < num; i++)
    {
        printf("%s ", s[i].name);
    }
	return 0;
}
int int_cmp(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
int cmp_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int cmp_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int cmp_double(const void* e1, const void* e2)
{
    return *(double*)e1 > *(double*)e2 ? 1 : 0;
}
void bubble_qsort(const void* arr, int num, int width, int(*p)(void*, void*))
{
	int i = 0;
	int j = 0;
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - 1 - i; j++)
		{
			if (p((char*)arr + width * j, (char*)arr + width * (j + 1)) > 0)
			{
				swap((char*)arr + width * j, (char*)arr + width * (j + 1), width);
			}
		}
	}
}
void swap(char* n1, char* n2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char temp = *(n1 + i);
		*(n1 + i) = *(n2 + i);
		*(n2 + i) = temp;
	}
}

运行结果图:
结果图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值