【C语言】进阶版冒泡排序(qsort函数思想)

目录

冒泡排序

冒泡排序的实现代码

冒泡排序的缺点

qsort函数

qsort函数

void*指针

qsort使用实例

进阶版冒泡排序

代码实现

代码分析   

Bubble_Sort函数

Swap函数


        既然要介绍进阶版的冒泡排序,我们就要先知道冒牌排序的实现方式,以及冒泡排序的缺点,我们才能对其进行改进。

冒泡排序

冒泡排序的实现代码

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>

int main()
{
	int arr[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
	int i,j,k = 0;
	int tmp = 0;
	for (i = 0; i < 9; i++)    //因为数组下标从0开始,到9正好是个元素
	{
		for (j = 0; j< 9 - i; j++)    //当进行到第i次冒牌时候,前i个最大的元素已经在之前的排序中排好放在序列尾部了
		{
			if (arr[j] > arr[j + 1])
			{
			tmp = arr[j];
			arr[j] = arr[j+ 1];
			arr[j + 1] = tmp;
			}
		}
	}
	for (k = 0; k < 10; k++)
	{
		printf("%d ",arr[k]);
	}
	return 0;
}

冒泡排序的缺点

        有上述代码可以看出,冒泡排序只能对一种类型的数据进行排序。这次排序的数据类型是int,但我下次要排序的数据类型变成float时,我就要重新修改代码。代码的普适性不好。

        那么有没有什么解决办法呢?当然是有的。而且早就被大佬们封装好放在编译器中了。这个函数就是qsort函数。

qsort函数

qsort函数

是一个基于快速排序法的函数。

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

      1.  头文件-#include<stdlib.h>

      2. base-要排序数组的首地址

      3.num-数组元素个数,用sizeof(arr)/sizeof(arr[0])计算

      4.size-数组中每个元素所占的字节,用sizeof(arr[0])计算

      5.int(*compar)(const void* e1, const void* e2)

     compar是一个函数指针,指向比较两个元素所用的函数的地址,指向的函数类型为int()(const void* e1, const void* e2),这个函数要使用者自己实现

     *e1和*e2是需要排序的数组中待比较的两个元素的地址,该函数的返回值需要遵循以下规则:

               1. *e1>*e2,返回值大于0(返回值类型为int)

               2. *e1<*e2,返回值小于0

               3. *e1=*e2,返回值等于0

               4.强制类型转换时,类型应该为实参的类型

void*指针

        void* 因为没有规定地址的大小,所以可以接受接受任意类型的指针。但正因为未规定大小,所以不能进行解引用操作,因为不知道要解引用几个字节。同理,也不能进行加(减)整数的操作。

        所以在进行解引用使用时,要进行强制类型转换。转换的类型要与实参的类型相同。

qsort使用实例

        里面有两个例子。test1是将结构体变量按照年龄排序,test2是将结构体变量按照名字排序。         (tips: *e1-*e2 升序排列;*e2-*e1 降序排列)

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct Stu    //创建结构体变量
{
	char name[20];
	int age;
};

int cmp_stu_by_age(const void* e1, const void* e2)    //自定义的比较函数1
{
    //将void*类型的指针进行强制类型转换,转换的类型与实参相同,即结构体指针(Struct Stu*)
    //因为访问结构体成员的特殊性,所以是如下的写法
    //如果是实参是int*类型的,那就要进行解引用
    //代码要写成这种形式 return *((int*)e1) - *((int*)e2);
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;    //访问结构体成员的第1种方法
                                                               //1.结构体指针->成员                                              
}

int cmp_stu_by_name(const void* e1, const void* e2)    //自定义的比较函数2
{
	//比较名字就是比较字符串
	//比较字符串不能用>=<,应该用strcmp函数
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name); 
}

void test1()
{
	struct Stu s[3] = { {"zhangasn", 20}, {"lisi", 30}, {"wangwu", 10}};
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
	int j = 0;
	for (j = 0; j < sz; j++)
	{
		printf("%s\n", s[j].name);    //访问结构体成员的第2种方法  2.结构体变量.成员
	}
}

void test2()
{
	struct Stu s[3] = { {"zhangasn", 20}, {"lisi", 30}, {"wangwu", 10} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
	int j = 0;
	for (j = 0; j < sz; j++)
	{
		printf("%s\n", s[j].name);
	}
}

int main()
{
	test1();
	test2();
	return 0;
}

进阶版冒泡排序

        使用改进版的冒泡函数完成qsort函数的功能,使其能够对所有类型的数据进行排序。

代码实现

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<string.h>

struct Stu
{
	char name[20];
	int age;
};

int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

void Swap(char* ele1, char* ele2, int width)	//一个字节一个字节的进行交换
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *ele1;
		*ele1 = *ele2;
		*ele2 = tmp;
		ele1++;
		ele2++;
	}

}

void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	for (i = 0; i < sz-1; i++)
	{
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

void test()
{
	struct Stu s[3] = { {"zhangasn", 20}, {"lisi", 30}, {"wangwu", 10} };
	int sz = sizeof(s) / sizeof(s[0]);
	bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);
	int j = 0;
	for (j = 0; j < sz; j++)
	{
		printf("%s\n", s[j].name);
	}
}

int main()
{
	test();
	return 0;
}

代码分析   

    该代码的重点是Swap函数与bubble_sort函数的编写。通过bubble_sort和Swap函数实现qsort函数的功能。

Bubble_Sort函数

void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	for (i = 0; i < sz-1; i++)
	{
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

        base是要进行排序的目标数组的首元素地址,但是因为是void*类型的指针,我们不知道目标数组中的元素地址到底占用多少字节。

        sz是数组的元素个数,使用sizeof函数求得。sz=sizeof(数组名)/sizeof(数组首元素);

        sz-1就是冒泡排序要进行的趟数。

        width是数组中每个元素占用的字节数。

        cmp是函数指针,指向不同的cmp函数就有不同排序条件。该代码的指向的排序条件就分别是cmp_stu_by_age函数和cmp_stu_by_name函数。

难点:

        为了解决不知道数组中元素地址大小的问题,我们引入了width。只要知道了数组的起始地址以及每个元素占用的字节数。就能用最小的单位(char类型,占用1字节)将每个元素的地址表示出来。例如,s[1]元素的地址就是首地址地址+1*width,即&s[1] = base+1*width

        同理可得数组中任意元素的地址。&s[j] = base+j*width

        将两个元素进行比较,如果前一个元素比较打,就将两元素进行交换。这就涉及到Swap函数。

Swap函数

void Swap(char* ele1, char* ele2, int width)	//一个字节一个字节的进行交换
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *ele1;
		*ele1 = *ele2;
		*ele2 = tmp;
		ele1++;
		ele2++;
	}

}

        我们面临和上面一样的问题,就是不知道每个元素的地址,无法完成交换。

        既然面对的问题一样,那解决问题的方法也一样。

        在传参时,我们将元素的占用的字节数width也传入Swap函数中。使用最小的单位,一个字节一个字节的交换,交换的次数就是元素的字节数。当这两个元素每个字节的内容都被交换了,这两个元素也就被交换了。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言数组排序函数qsort是标准库函数,用于对数组进行排序。它的使用方法是通过传入一个比较函数来指定排序的规则。在给出的代码中,我们可以看到使用qsort函数对一个整型数组进行升序排序的例子。\[1\] 为了实现qsort函数的功能,我们可以使用一种较为简单的排序算法,比如冒泡排序算法来模拟实现一个具有排序数组、字符串、结构体等功能的bubble_sort函数。\[2\]这个函数的参数可以仿照qsort函数的参数,包括要排序的数组的起始地址、元素个数、每个元素的大小以及一个比较函数。\[3\] 具体实现bubble_sort函数函数体可以根据冒泡排序算法来编写,通过比较相邻的元素并交换位置来实现排序。排序的规则可以通过比较函数来指定,根据需要可以实现升序或降序排序。 总结起来,qsortC语言标准库中的数组排序函数,可以通过传入比较函数来指定排序规则。如果想要模拟实现类似功能的排序函数,可以使用一种简单的排序算法,比如冒泡排序,并根据需要实现相应的比较函数。 #### 引用[.reference_title] - *1* *2* *3* [【C语言qsort()函数详解:能给万物排序的神奇函数](https://blog.csdn.net/weixin_72357342/article/details/130628874)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值