qsort函数介绍和模仿qsort的功能实现一个通用的冒泡排序

        我们都知道排序一个数组的方法有很多种,下面我介绍一下用qsort函数来排序一个数组。

        一.qsort函数基本内容

        我们先看一下qsort函数的原型

void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
  • 头文件--#include<stdilb.h>
  • base -- 指向要排序的数组的第一个元素的指针。
  • nitems -- 由 base 指向的数组中元素的个数。
  • size -- 数组中每个元素的大小,以字节为单位。
  • compar -- 着重理解,这个函数是需要用户自己定义,它用来比较两个元素的函数。它是函数指针类型 ,这个函数指针指向的函数,能够比较base指向数组中的两个元素,const是为了需要让两个比较的数值不被修改, 

         自己定义的compar函数通用(模板)可以这么写

//升序
int compareMyType (const void * a, const void * b)
{
    if ( *(MyType*)a <  *(MyType*)b ) return -1;
    if ( *(MyType*)a == *(MyType*)b ) return 0;
    if ( *(MyType*)a >  *(MyType*)b ) return 1;
}

//降序
int compareMyType (const void * a, const void * b)
{
    if ( *(MyType*)a >  *(MyType*)b ) return -1;
    if ( *(MyType*)a == *(MyType*)b ) return 0;
    if ( *(MyType*)a <  *(MyType*)b ) return 1;
}

//其实上面也可以改为,这样看着更简洁
int compareMyType (const void * a, const void * b)
{
      return ( *(MyType*)a -  *(MyType*)b );//升序
    //return ( *(MyType*)a -  *(MyType*)b );//降序
} 

   注 :①size_t表示类型是无符号整数

        ②为什么是用void*类型的指针,因为该函数不知道你想排序的是什么类型的数组,所以这种类型的指针可以接受任意类型的地址,而且该类型的指针不能进行解引用也不能进行指针的运算

        ③顺带在这里提一下(后面模拟实现qsort函数的实现会用到),char*类型的指针进行解引用操作时访问的是一个字节int*类型的指针进行解引用操作时访问的是四个字节。即指针类型可以决定指针解引用时访问几个字节。

        二.下面看一下qsort函数的基本应用(默认是升序)

                排序整形数组

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int cmp_int(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}
int main()
{
	int i = 0;
	int a[] = { 4,1,24,55,13 };
	int sz = sizeof(a) / sizeof(a[0]);
	qsort(a, sz, sizeof(int), cmp_int);
	for (i = 0; i < sz; i++)
	{
		printf("%d ",a[i]);
	}
    //排序后结果 1 4 13 24 55
}

                 排序结构体数组

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Stu
{
	char name[20];
	int age;
};
int cmp_stu_age(const void* p1, const void* p2)
{
	return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
int main()
{
	int i = 0;
	struct Stu a[] = { {"GGbond",18},{"Sheep",21},{"Tiger",15 }};
	int sz = sizeof(a) / sizeof(a[0]);
	qsort(a, sz, sizeof(a[0]), cmp_stu_age);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", a[i].age);
	}
    //排序后结果 15 18 21
}

         三.模仿qsort的功能实现一个通用的冒泡排序(升序)

        假设我们没有学习快速排序的算法,所以我们用冒泡函数的思想模拟实现类似qsort函数

        这里我们拿整形数组来做例子,首先主函数内容就不赘述了,都看得懂,主要是bubble_sort这个函数怎么设计,首先可以明确因为模拟的是qsort函数,所以bubble_sort函数的参数要和qsort函数的参数形式上要一致,但是函数内部怎么设计呢,可以知道主体肯定是冒泡排序,如下

void bubble_sort(void* base, int sz, int size, int(*cmp)(const void*, const void*))
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)//躺输
	{
		for (j = 0; j < sz - 1 - i; j++)//一趟比较的对数
		{
			
		}
	} 
}
int main()
{
	int i = 0;
	int a[] = { 3,1,6,12,42,4 };
	int sz = sizeof(a) / sizeof(a[0]);
	bubble_sort(a, sz, sizeof(int), cmp_int);
	for (i = 0; i < sz; i++)
	{
		printf("%d ",a[i]);
	}
}

        问题就来了,应该添加什么判断条件来对数组中要比较的两个数值进行排序呢?我们知道,一个整形数字在内存中占4个字节,如下图所示

        而后我们再看到 int(*cmp)(const void*, const void*),cmp这个指针保存的是哪个函数,就是用来比较两个数值大小的函数啊!那不就是上面提到的吗!

int cmp_int(const void* p1, const void* p2)
{
    return (*(int*)p1 - *(int*)p2);
}

        好了到这里我们已经可以判断这两个数值的大小关系了,但是我们还缺个交换两个数值的函数啊!那怎么设计这个函数呢?我们再看到int cmp_int(const void* p1, const void* p2)这个函数的参数类型是const void*,接收的是地址,而且void* base指向的是数组首地址 ,而且整数在内存中是以字节为单位储存的,你想准确的操作某个数值的地址,是不是要用到指针变量啊,那用什么类型的指针变量呢?肯定是char*类型的啊,因为char*类型的指针进行解引用操作时访问的是一个字节,一是任何数字的倍数吗,所以最准确。

        所以设计一个Swap函数进行交换两个数值,而且这个函数不仅要其中两个参数是接受两个数值的地址,还要一个参数是接受数值的大小(字节为单位),然后我们就可以通过一个for循环进行两个数值之间每个字节之间的交换,最终4个字节交换完之后,两个数值也就成功进行交换了

        代码如下

void Swap(char* b1, char* b2,int size)
{
	int i = 0;
	char t = 0;
	for (i = 0; i < size; i++)
	{
		t = *b1;
		*b1 = *b2;
		*b2 = t;
		b1++;
		b2++;
    }
}
void bubble_sort(void* base, int sz, int size, int(*cmp)(const void*, const void*))
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if(cmp((char*)base+j*size,(char*)base + (j+1) * size)>0)
			{
				Swap((char*)base + j * size, (char*)base + (j + 1) * size,size);
			}
		}
	} 
}
int main()
{
	int i = 0;
	int a[] = { 3,1,6,12,42,4 };
	int sz = sizeof(a) / sizeof(a[0]);
	bubble_sort(a, sz, sizeof(int), cmp_int);
	for (i = 0; i < sz; i++)
	{
		printf("%d ",a[i]);
	}
}

        再看下图如何进行数值交换的

         

       最后的最后,谢谢你的阅读,如有错误,恳请指正,再次谢谢!

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值