运用库函数qsort的思想升级冒泡排序

谈到了qsort (quick sort)库函数,我们就先来了解一下,qsort 是一个用来排序的库函数,底层原理是通过快速排序来进行的.他的功能并不像冒泡排序一样只能排整数,它可以进行任意类型的排序(类型您来定)

qsort函数的认识

在MSDN上查一下

需要的头文件有两个(其中一个就可以)

 无返回值,有四个参数,类型分别是无类型指针、无符号整型、无符号整型、函数指针.并且这个函数指针的两个参数类型都是常量我类型指针,返回类型是整型。

名词介绍 

 待排序的数组的起始地址。

待排序数组元素的个数 。

 待排序数组每个元素的大小(字节单位)。

 指向一个可以比较两个元素大小的函数(您想让他按照什么标准进行比较)

参数四解析

 参数四是由一个函数指针接收,故调用是需要传一个函数地址进去,qsort既然是排序库函数,则肯定就少不了比较大小这一项,可是比较结果怎么展示呢,难道像冒泡排序一样用 > < = 吗,当然不是,否则功能不就被限制于比较数字大小了吗,所以就由返回值来判断大小,返回的数字与0比较,从而判断大小。


用qsort库函数实现冒泡排序

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

int com(const void* p1, const void* p2)//p1与p2实际就是arr中待比较的元素
{
	return *(int*)p1 - *(int*)p2;//?
}

int main()
{
	//void qsort(void* base, size_t num, 
	//									size_t width,			
	//	int(__cdecl * compare)(const void* elem1, const void* elem2));


	int arr[10] = { 3,7,5,9,0,2,4,6,8,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), com);//传自己定的函数com
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

这里为什么要强制类型转换呢,在博主之前的文章之中也曾提到解引用(*)操作所访问的空间取决于它的类型,但是它是一个void* 的类型,无具体类型指针,所以在解引用(*)时,编译器就很困惑,不知访问几个字节的空间,因此也不可以 + - 整数。所以就有把 p 强制类型转换成 int* 。

那么 void* 为什么不换成 int* 呢,那就是开发者的智慧了,因为你不一定是比较整型啊,可能比较什么其它类型的嘛。所以就统一用 void* 更合理。

qsort库函数是默认排成升序的,想要排成降序就将 p1 与 p2 的位置交换一下。


用qsort库函数实现结构体排序

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

struct ide
{
	char name[20];
	short age;
};
int cmp(const void* p1,const void* p2 )//固定形式
{
	//return (*(struct ide*)p1).age - ((struct ide*)p2)->age;//结构体的两种写法

	return strcmp((*(struct ide*)p1).name, ((struct ide*)p2)->name);//比较字符用strcmp
}

int main()
{
	struct ide man[] = { { "zhangsan",18 },{ "lisa",37 }, { "wanghu",23 } };//结构体数组
	int sz = sizeof(man) / sizeof(man[0]);
	qsort(man, sz, sizeof(man[0]), cmp);
	for (int i = 0; i < sz; i++)
	{
		printf("%d %s\n", man[i].age,man[i].name);//man[i]就是对应的结构体
	}
		
	return 0;
}


升级冒泡排序

我们想让冒泡函数也有 qsort 函数一样的功能那么就要借鉴一波 qsort 函数的实现了。

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

void swap(char* a, char* b,size_t n)//通过单位大小知道访问多少字节空间
{
	for (int i = 0; i < n; i++)
	{
		char tmp = *a;
		*a = *b;
		*b = tmp;
		a++; b++;
	}
	
}
void pul(void* base, size_t num, size_t width, int(*pc)(void* p1, void* p2))
{
	int i, j;
	for (i = 0; i < num-1; i++)//冒泡次数
	{
		for (j = 0; j < num - 1 - i; j++)//每一次
		{
			if (pc((char*)base+j*width,(char*)base+(j+1)*width)>0)//强转成char*的指针,好计算跳过的字节个数,大于0就交换,故达到了升序目的
			{
				swap((char*)base + j * width, (char*)base + (j + 1) * width,width);//将单位大小也传过去
			}
		}
	}

}

struct ide
{
	char name[20];
	short age;
};

int com(const void* p1, const void* p2)//这是你自己需要写的函数,给一个比较标准
{
	//return *(int*)p1 - *(int*)p2;
	return strcmp((*(struct ide*)p1).name, (*(struct ide*)p2).name);
}

int main()
{
	struct ide arr[] = { {"wanggang",25},{"lihu",18},{"niuma",32} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	pul(arr, sz, sizeof(arr[0]), com);//自己定义一个函数pul实现qsort的功能。
	for (int i = 0; i < sz; i++)
	{
		printf("%s %d\n", arr[i].name, arr[i].age);
	}

	return 0;
}

 这里其实使用到了回调函数,回调函数在这里就不说了,有很多其它博主都讲得超详细的。

猜你喜欢

转载自blog.csdn.net/C_Rio/article/details/129224439