qsort函数-详细讲解及冒泡排序模拟

大家好,这里是小bang子,今天给大家讲讲C语言编译器函数自带库自带的qsort排序函数。


目录

1.回调函数

1.1 qsort函数声明

1.2 qsort函数示例 

 1.3比较函数示例

2.模拟冒泡bubble


1.回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个
函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数
的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进
行响应。

qsort函数中的比较函数就是一个回调函数,qsort包含在

1.1 qsort函数声明

void qsort( void *base,

                    size_t num,

                    size_t width,

                    int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

base——待排序数组首元素的地址

num——待排序数组的长度(元素个数)

width——待排序元素字节大小

compare——比较函数指针

compare的参数因为不知道具体数据类型,在设计的时候用void*来表示,使用时在compare函数内部根据数据类型进行强制转换比较大小。

Return Value Description
< 0 elem1 less than elem2
0 elem1 equivalent to elem2
> 0 elem1 greater than elem2

1.2 qsort函数示例 

#include
#include
//比较函数,根据需要自己建立
int cmp_int(const void* elem1,const void* elem2)
{
    return (*(int*)elem1-*(int*)elem2);
}
//打印数组
void print_int_arr(int* arr, int sz)
{
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", *(arr + i));
	}
	printf("\n");
}

int main()
{
    int arr[10]={9,8,7,6,5,4,3,2,1,0};
    int sz=sizeof(arr)/sizeof(arr[0]);
    qsort(arr,sz,sizeof(arr[0]),cmp_int);
    print_int_arr(arr,sz);
    return 0;
}

 比较函数中第一个减第二个元素默认升序排序,若需降序只用把两个元素交换位置,用第二个元素减第一个元素,qsort函数中自带的有交换函数,我们只需要创建比较函数。

 1.3比较函数示例

比较int类型

int cmp_int(const void* elem1,const void* elem2)
{
    return (*(int*)elem1-*(int*)elem2);
}

比较结构体中关键字

struct stu
{
	char name[10];
	int age;
	double score;
};
int cmp_stu_age(const void* e1, const void* e2)
{
    //强制转换成结构体指针进行访问
	return (((struct stu*)e1)->age-((struct stu*)e2)->age);
}

比较结构体中字符串,用库文件

struct stu
{
	char name[10];
	int age;
	double score;
};
int cmp_stu_name(const void* e1, const void* e2)
{
	return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}

2.模拟冒泡bubble

qsort是基于快速排序的方法,我们这里模仿qsort的实现方法模拟个冒泡排序。

参数一致,采用冒泡排序

void bubble_sort(void* base, int num, int width, int(*cmp)(const void* e1, const void* e2))
{
	for (int i = 0; i < num-1; i++)
	{
		int j = 0;
		for (j=0;j < num - 1 - i; j++)
		{
			//比较2数大小读取字节方式跳过数
			if (cmp_int((char*)base+j*width,(char*)base+(j+1)*width)>0)
			{
				//交换函数
				swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
			}
		}
	}
}
//交换函数,char*读取一个字节,buf1存第一个数第一个字节的地址,buf2存第二个数第一个字节的地址
void swap(char*buf1,char*buf2,int width)
{
	for (int i = 0; i < width; i++)
	{
		int tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}

我们来讲解下这里面width的用法,以及base为啥要强制转换成char*类型。

首先数据在内存中是以字节存储的,1个int类型占4个字节,并且在vs编译器中是以小端字节序存储,如果不知道小端字节序存储可以查看下我发的一篇大小端字节序存储了解下https://mp.csdn.net/mp_blog/creation/editor/123193426

画图讲解下,假设待两个相邻的排序数字是4和5,在内存中如下存储

qsort函数-详细讲解及冒泡排序模拟_第1张图片

 在冒泡中将base转换成char*类型,访问一个字节,然后通过数据字节大小width,实现指向下一个数据。

在交换函数swap中利用width实现将数据的每一个字节进行交换,达成交换数据的目的。

qsort函数-详细讲解及冒泡排序模拟_第2张图片

qsort函数-详细讲解及冒泡排序模拟_第3张图片 

qsort函数-详细讲解及冒泡排序模拟_第4张图片 

qsort函数-详细讲解及冒泡排序模拟_第5张图片 

 这样就实现了数据的交换。

示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include
#include

struct stu
{
	char name[10];
	int age;
	double score;
};

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

//交换函数,char*读取一个字节,buf1存第一个数第一个字节的地址,buf2存第二个数第一个字节的地址
void swap(char*buf1,char*buf2,int width)
{
	for (int i = 0; i < width; i++)
	{
		int tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}

void print_stu_name(struct stu* arr, int sz)
{
	for (int i = 0; i < sz; i++)
	{
		printf("%s ", (arr + i)->name);
	}
	printf("\n");
}

void bubble_stu_name_sort(void* base, int num, int width, int(*cmp)(const void* e1, const void* e2))
{
	for (int i = 0; i < num - 1; i++)
	{
		int j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//比较2数大小读取字节方式跳过数
			if (cmp_stu_name((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				//交换函数
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

void test2()
{
	struct stu arr2[3] = { {"zhangsan",19,88},{"lisi",15,70},{"langwu",24,68} };
	int sz = sizeof(arr2) / sizeof(arr2[0]);
	bubble_stu_name_sort(arr2, sz, sizeof(arr2[0]), cmp_stu_name);
	print_stu_name(arr2, sz);
}

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

qsort函数-详细讲解及冒泡排序模拟_第6张图片


以上就是这次qsort函数的分享,感谢大家的观看。

你可能感兴趣的:(c语言,排序算法)