用冒泡排序来模拟qsort函数

文章目录

#1.复习冒泡排序

#2. 讲解qsort函数

#3. 用冒泡排序来模拟qsort函数

1. 复习冒泡排序

参考这篇文章:      写文章-CSDN创作中心   

先说一下原始冒泡排序的问题,如果一个数组是排好序的,那么这个冒泡函数还是会进行一趟一趟的冒泡排序,一次一次的比较,代码效率过于低,将代码改成如下的形式, 升级版的冒泡排序 :

void bubble_sort(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int flag = 1;    //假设数组是排好序的
		int j = 0;
		for (j = 0; j < sz - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;
			}
		}
		if (flag == 1)      //数组确实是有序的,不用进行下一趟的排序,排序效率提高
		{
			break;
		}
	}
}
int main()
{
	//int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };


	int sz = sizeof(arr) / sizeof(arr[0]);

	bubble_sort(arr, sz);

	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

定义一个flag变量,如果一趟冒泡排序下来一对元素都没有进行交换,那么就说明这个数组是排好序的,就不会进行下一趟的冒泡排序直接跳出循环,代码效率提高

2. 讲解qsort函数

是C语言中的一个排序函数,可以对任意的数据类型进行排序,默认排序成升序

如果比较2个整型元素,elem1指向一个整数 elem2指向另一个整数

 

qsort函数的用法,代码演示如下:

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

int cmp_int(const void* e1, const void* e2)
{
	return(*(int*)e1 - *(int*)e2);      //排成升序
}

int main()
{
	int arr[] = {9,8,7,6,5,4,3,2,1,0};  //排成升序

	//0 1 2 3 4 5 6 7 8 9
	//把数组排成升序
	int sz = sizeof(arr) / sizeof(arr[0]);

	int i = 0;
	qsort(arr, sz, sizeof(arr[0]), cmp_int);

	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

自己提供一个cmp_int函数,根据qsort的返回值,只需将cmp_int函数的返回值设置成一个元素减一个元素即可,即元素1>元素2,返回>0;即元素1<元素2,返回<0;即元素1=元素2,返回=0;

这里需要注意的是编写的cmp_int函数的参数是void*类型,void*是无具体类型的指针,可以接受任意类型的地址,不能解引用操作, 也不能+-整数,所以对其解引用时需要强制类型转换成int*类型

还可以对结构体中的成员变量进行排序,代码演示如下:

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

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

int cmp_stu_by_name(const void* e1, const void* e2)
{
	//strcmp --> >0 ==0 <0
	return  strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

void test2()
{
	//测试使用qsort来排序结构体数据
	struct Stu s[] = { {"zhangsan", 15}, {"lisi", 30}, {"wangwu", 25} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);

}

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

当然同样需要将void*指针强制类型转换成(struct Stu*)的类型,注意在比较字符串长度的时候不能直接比较需要用strcmp函数比较

总结:使用qsort函数时需要自己提供一个比较函数来进行比较

3.用冒泡排序来模拟qsort函数

1.首先来学习qsort函数的参数是如何编写的,模仿qsort函数的参数来编写冒泡函数的参数

2.其次整个冒泡排序的大框架不用改变,只是一对一对元素进行比较时要修改,在比较元素是我们是不知道这个元素的数据类型的(也就是不知道这个元素是几个字节的),那么怎么找到一个元素呢 ,就需要强制类型转换成char*类型的,然后去乘以宽度就能找到这一个元素,因为char是一个字节比较方便

3.如果第一个元素大于第二个元素就会进入if语句后交给Swap函数来进行元素的交换,Swap函数交换的时候因为已经将void*指针强制类型转换成char*了,就直接用char*的指针来接收,交换的时候,需要创建临时变量在宽度的范围内进行一个字节一个字节的交换

以一个整型数组为例,代码如下:

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

int cmp_int(const void*e1, const void*e2)
{
    return(*(int*)e1-*(int*)e2);
}
void Swap(char*buff1, char*buff2, int width)
{
    int i=0;
    for(i=0;i<width;i++)
    {   
       char tmp=*buff1;
       *buff1 =*buff2;
       *buff2 = tmp;
       buff1++;
       buff2++;
    }
}

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 flag = 1;    //假设数组是排好序的
		int j = 0;
		for (j = 0; j < sz - i - 1; j++)
		{
			if(cmp((char*)base+j*width,(char*)base+(j+1)*width)>0)
			{
				Swap((char*)base+j*width,(char*)base+(j+1)*width, width);
                flag=0;
			}
		}
		if (flag == 1)      //数组确实是有序的,不用进行下一趟的排序,排序效率提高
		{
			break;
		}
	}
}
void test3()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };

	int sz = sizeof(arr) / sizeof(arr[0]);

	bubble_sort(arr, sz,sizeof(arr[0]), cmp_int);

	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

}
int main()
{
    test3();

    return 0;
}

结构体成员排序的代码如下:

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

struct Stu
{
	char name[20];
	int age;
};
int cmp_stu_by_name(const void* e1, const void* e2)
{
	//strcmp --> >0 ==0 <0
	return  strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
void Swap(char* buff1, char* buff2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *buff1;
		*buff1 = *buff2;
		*buff2 = tmp;
		buff1++;
		buff2++;
	}
}
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 flag = 1;    //假设数组是排好序的
		int j = 0;
		for (j = 0; j < sz - i - 1; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
}
void test4()
{
	struct Stu s[] = { {"zhangsan", 15}, {"lisi", 30}, {"wangwu", 25} };
	int sz = sizeof(s) / sizeof(s[0]);
	bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_name);
	bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}
int main()
{
	test4();

	return 0;
}

总结:冒泡排序模拟qsort函数时,整体的大框架比较、交换都是相同的,就是在比较函数cmp上写法上有些不同

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值