【C语言】qsort快速排序的原理_模拟实现_冒泡排序

1.qsort函数的使用

cplusplus上对这个库函数的阐释:
在这里插入图片描述
作用:实现一个数组内元素的排序

书写形式

void qsort (void* base, size_t num, size_t size,
            int (*compar)(const void*,const void*));

参数

  1. void base*:表示数组中第一个元素的地址,此处用 void* 类型是为了迎合不同类型的比较,比如:整型,结构体等
  2. size_t num:表示一个数组中的元素个数,因为个数是非负整数,所以用了 size_t定义
  3. size_t size:表示要比较的数组中一个元素占内存的大小,单位是字节
  4. int ( * compar)(const void*,const void*) :表示函数指针,返回类型是 int ,参数是要比较元素的地址,compar函数内部一般需要强制类型转换,因为 void*无法解应用

返回值
在这里插入图片描述
应用举例

#include<stdio.h>
#include<stdlib.h>
int int_compar(const void*e1,const void* e2)
{
	return (*(int*)e1 - *(int*)e2);//强制类型转换,解应用
}
int main()
{
	int arr[] = { 2,5,4,6,9,7,8,3,1 };
	qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]),
	 int_compar);
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

在这里插入图片描述

2.qsort函数的模拟实现:

使用回调函数,用冒泡排序的方式实现,能排任意类型
(冒泡排序详解链接在下,模糊可以去看看)
http://t.csdn.cn/Q0n0q

在这里插入图片描述
这是原始冒泡排序的写法
将其改造为qsort函数排法,要改造:
1.改参数
2.改比较方法
3.改互换方法

2.1改参数:

模仿qsort 函数:

void qsort (void* base, size_t num, size_t size,
            int (*compar)(const void*,const void*));
  • int* arr 改为 void* base 接受任何类型的变量
  • int sz其实不用改,也可以写成 size_t sz
  • 只知道首元素地址和元素个数,但一个元素的内存大小还不知道,无法定位,因此要加入变量: size_t width
  • 排序方法不能简单的跟排整形的一样,所以排序方法要单独封装一个函数:加入变量 int (*cmp)(const void *)(const void * )

改造后:

void bulle_sort(void* base, size_t sz, size_t  width,
   int (*cmp)(const void*e1,const void*e2))

2.2改判断方法:

在这里插入图片描述
重点是这里的参数传什么
也就是用什么计算方式来遍历数组中元素?
一个字节一个字节地访问
来个 char* 类型,括号内参数如下:

(char*)base+j*width,(char*)base+(j+1)*width

强制类型转换为 char指针:
char
类型 + 4 表示跳过 4 个字节
然而 int* 类型 + 4 表示跳过 4 个 int所占内存的大小,也就是 16个字节

判断方法改后如下:
在这里插入图片描述

2.3 改交换方式:

封装swap()函数实现元素交换,这里举例比较整型数组,和结构体中名字的长短

void swap(char* e1,char* e2,size_t width)
{
	int i = 0;
	for (i = 0;i < width;i++)
	{
		char tem = 0;
		tem = *(e1 + i);
		*(e1+i) = *(e2 + i);
		*(e2+i) = tem;
	}
}

这里采用的方式是一个字节一个字节地交换:

在这里插入图片描述

3.成品展现:

排序整型数组,结构体:

#include<stdio.h>
void swap(char* e1,char* e2,size_t width)
{
	int i = 0;
	for (i = 0;i < width;i++)
	{
		char tem = 0;
		tem = *(e1 + i);
		*(e1+i) = *(e2 + i);
		*(e2+i) = tem;

	}
}
void bubble_sort(void* base, size_t sz, size_t  width,
	int (*cmp)(const void*e1,const void*e2))
{
	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 * width, (char*)base + (j + 1) * width) > 0)
			{
				swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
			}
		}
	}

}
//初始化结构体
struct Stu
{
	char name[20];
	int age;
};
//比较整型
int int_cmp_1(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}
//比较年龄
int int_cmp_2(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
//比较名字长短
int char_cmp_3(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
//打印整型数组
void Printf_int(int* arr, int sz)
{
	int i = 0;
	for (i = 0;i < sz;i++)
		printf("%d ", arr[i]);
	printf("\n");
}
//打印结构体名字
void Printf_char_name(struct Stu* arr, int sz)
{
	int i = 0;
	for (i = 0;i < sz;i++)
	{
		printf("%s ", arr[i].name);
	}
	
	printf("\n");
}
//打印年龄
void Printf_int_age(struct Stu* arr, int sz)
{
	int i = 0;
	for (i = 0;i < sz;i++)
	{
		printf("%d ", arr[i].age);
	}
	
	printf("\n");
}
//测试整型数组
void test_int_arr(int* arr1, int sz1)
{
	bubble_sort(arr1, sz1, sizeof(arr1[0]), int_cmp_1);
	Printf_int(arr1, sz1);
}
//测试年龄
void test_stu_age(struct Stu* arr2, int sz2)
{
	bubble_sort(arr2, sz2, sizeof(arr2[0]), int_cmp_2);
	Printf_int_age(arr2, sz2);

}
//测试名字
void test_stu_name(struct Stu* arr2,int sz2)
{
	bubble_sort(arr2, sz2, sizeof(arr2[0]), char_cmp_3);
	Printf_char_name(arr2, sz2);
}
int main()
{
	int arr1[10] = { 2,5,4,6,9,7,8,3,1,0 };
	struct Stu arr2[] = { {"zhangsan",20},{"lisi",15},{"wangwu",30} };
	int sz1 = sizeof(arr1) / sizeof(arr1[0]);
	int sz2 = sizeof(arr2) / sizeof(arr2[0]);
	 test_int_arr(arr1, sz1);
	 test_stu_age(arr2, sz2);
	 test_stu_name(arr2, sz2);
	 return 0;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值