C语言排序:冒泡排序 , qsort函数

目录

一,冒泡排序

1.1冒泡排序思想

1.2 代码实现

二,qsort()函数

2.1 qsort函数的概念

2.2 qsort函数的使用

2.2.1 qsort数组排序

2.2.2 qsort排序结构体

三,模拟实现qsort(采用冒泡的方式)


前言

        这篇文章中你能学习到冒泡排序的思想,以及它的实现方式。了解到qsort()函数的使用,以及怎么用冒泡排序的实现模拟实现qsort()函数。这篇文章需要掌握一定的指针知识,如果有不够熟悉指针的朋友可以看看我往期指针的文章,有助于加深理解。

一,冒泡排序

1.1冒泡排序思想

        对一个无序数组的第一个元素的位置开始,进行两两比较,根据大小交换位置,直到最后将最大 (小)的数交换到了无序队列的队尾,第一趟结束后,第二趟依旧从第一个元素开始排起排到倒数第二个元素结束,第三趟排到到数第三个元素结束,依次类推。

为什么第二趟要到倒数第二个结束,第三个要到倒数第三个元素结束呢?

因为每一趟排序就会把最大(小)值就会放在序列的最后,所以第一趟排完,最大(小)值就已经在最后了。

//这里使用冒泡排序排一组无序数列(降序)
  3    5    4    7    1    8    9    2    0    6
先从第一个数 3 开始,与下一个数比较大小,不满足条件,换位置,接着与下一个数继续比较,直到交换的队尾
 5    3    4    7    1    8    9    2    0    6 

//这里为了满足降序3 和 5交换
 5    4    3    7    1    8    9    2    0    6

//接着,3与下一位继续比较
 5    4    7    3    1    8    9    2    0    6

......

//第一趟排完

5   4     7   3     8    9     2    1    6    0

//第二趟

5   4     7    3     9    8     2    1   6    0

5    4    7    3     9    8      2    6   1   0

//第三趟,第四趟.......第九趟。

一个有n个元素的序列,需要排n-1趟。

1.2 代码实现

#include<stdio.h>
//bubble_sort
void bubble_sort(int arr[10], int sz)
{
	int i = 0;
	for (i = 0; i < sz - 1; i++) //总共遍历sz-1趟
	{
		int j = 0;
		for (j = 0; j < sz - i - 1; j++)//每趟进行比较
		{
			if (arr[j] < arr[j + 1])	//两两比较小的数放后面
			{
				int tmp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = tmp;
			}
		}
	}
	for (i = 0; i < sz; i++)	//排完打印
	{
		printf("%d ", arr[i]);
	}
	return 0;
}
int main()
{
	int arr[10] = { 5,4,7,3,1,8,9,2,0,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);//元素的个数
	bubble_sort(arr, sz);
	return 0;
}

二,qsort()函数

冒泡排序只能排序整型数组,而qsort函数非常灵活,能帮助我们排序不同类型的数组元素。

2.1 qsort函数的概念

函数声明:

void  qsort  (void* base,size_t num ,size_t size ,

                                int ( * compar)(const void*e1 ,const void*e2) );

//头文件:stdlib.h

        void* base 表示数组的起始位置,类型是 void*,size_t num 表示数组的元素个数,类型是unsigned int,size_t size表示的是一个元素的大小,单位是字节,后面的函数指针是指向两元素比较的函数,e1和e2是相比较的两元素的地址。

这里的指针的类型是void*,可以接受任意类型的地址。但是要注意两点:

1,void*指针不能直接解引用,需强制类型转换再解引用。

2,void*指针不能直接加减。

2.2 qsort函数的使用

2.2.1 qsort数组排序

例如一个对整型数组进行升序排列,那么比较函数为:

int  cmp_int( const void* e1, const void* e2)

{

        return *( int* ) e1 - *( int* )e 2;

}

例如一个对一个字符型数组进行升序排列(按照ASCII值),那么比较函数为:

int cmp_char( const void* e1, const void* e2)

{

        return *(char*)e2 - *(char*) e2;

}

//qsor排序整型数组(升序)
#include<stdlib.h>
int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
int main()
{
	int arr[10] = { 5,4,7,3,1,8,9,2,0,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);//元素的个数
	
	qsort(arr, sz, sizeof(arr[0]),cmp_int);

	int i = 0;
	for (i = 0; i < sz; i++)	//排完打印
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

2.2.2 qsort排序结构体

用qsort排序结构体,可以按照结构体里的任意元素排列。

例如:一个结构体里包含名字,年龄。如果分别按照年龄,名字排,那么比较函数分别为:

int  cmp_stu_by_age(const void*e1,const void*e2)        

{

        return ((struct stu*)e1)->age - ((struct stu*)e2 )->age;//按照年龄排

}

int cmp_stu_by_age(const void*e1,const void*e2)

{

        return  strcmp(((struct stu*)e1)->name-((struct stu*)e2) ->name);//利用strcmp函数来比较名字

}

//qsort比较结构体
struct stu
{
	char name[10];
	int age;
	char sex[10];
};
int cmp_age(const void* e1, const void* e2)
{
	return ((struct stu*)e1)->age - ((struct stu*)e2)->age;    //通过年龄比较
}
int main()
{
	struct stu s[3] = { {"张三",20,"男"},{"李四", 32,"男"},{"王五",23,"女"} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_age);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s    %d    %s \n", s[i].name, s[i].age, s[i].sex);
	}
	return 0;
}

三,模拟实现qsort(采用冒泡的方式)

        我们还创建一个无序数组来举例,构造bubble()函数排序,bubble接受的参数与qsort一样。但函数内部实现的过程用冒泡的方式来实现。

#include<stdio.h>
void swap(void* e1, void* e2, int size)
{
	int i = 0;
	for (i = 0; i < size; i++)	//一个字节一个字节的交换。。
	{
		char tmp = 0;
		tmp = *((char*)e1+i);  //加i是用来换下个字节来相加
		*((char*)e1+i) = *((char*)e2+i);
		*((char*)e2+i) = tmp;
	}

}
void bubble(void* base, size_t num, size_t size, int (*cmp)(const void*, const void*))
{
	int i = 0;
	for (i = 0; i < num - 1; i++) //num-1趟
	{
		int j = 0;
		for (j = 0; j < num - i - 1; j++)//一趟的过程
		{
			if (cmp((char*)base + j * size ,(char*)base + (j+1) * size )>0) //将地址转换为char*然后加上比较类型的大小乘以j,
				//用来与下一个类型的数比较
			{
				swap((char*)base + j * size, (char*)base + (j + 1) * size, size);	//将待交换的地址作为函数参数
			}
		}
	}

}
int int_cmp(const void* e1, const void* e2) //整型比较函数
{
	return *(int*)e1 - *(int*)e2; 
}
int main()
{
	int arr[] = { 1,3,5,7,9,2,4,6,8,0 };
	//char *arr[] = {"aaaa","dddd","ccccc","bbbb"};
	int i = 0;
	bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), int_cmp); //模拟实现qsort
	
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)	//打印
	{
		printf("%d ",arr[i]);
	}
	return 0;
}

如果需要比较字符型,结构体,只需要把整型比较函数换成对应的比较函数即可。

这上面的整型比较函数int_cmp()其实也是回调函数。

        回调函数是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

        回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

好了,到这里就结束了,希望对大家有所帮助!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会背雨霖铃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值