【C编程】冒泡排序算法与qsort()函数模拟实现

一、 冒泡排序

什么是冒泡排序?

“冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。它重复地走访过要排序>的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。”

请看图解:

在这里插入图片描述(注:图片来源于博客作者:烟雨倾城);

实现思路:

  • 由上面图解可知,每一趟冒泡排序都完成对一个数的排序;所以有n个数,就要执行n-1趟冒泡排序,而每一趟冒泡,都是相邻两个数比较,大的数放右边;由此可知,我们需要设置两个for循环,外层循环控制要执行几趟冒泡排序,内层循环来实现两数之间比较和交换;
  • 重点是控制两个for循环执行次数的语句:外层循环只需要执行n-1次;而对于内层循环,因为我们每一趟排序好一个数,所以我们交换两个数的次数是在减少的;所以内层for循环的控制语句应该是n-1-i次,第一趟需要交换n-1次,而第二趟排序,已经排序好了一个数,所以只需要交换n-1-1次,即n-1-i次;

算法实现:

//冒泡排序算法
#include<stdio.h>

//实现排序
void BubbleSort(int arr[], int sz)
{
    
    
	int i = 0;
	int j = 0;
	//第一步:外层for循环确定冒泡排序有几趟
	for (i = 0; i < sz - 1; i++)
	{
    
    
		//内层for循环来执行每一趟排序,交换两个元素
		for (j = 0; j < sz - 1 - i; j++)
		{
    
    
			//升序排列,交换两个元素
			if (arr[j] > arr[j + 1])
			{
    
    
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
//打印排序数组
Print(int arr[], int sz)
{
    
    
	int i = 0;
	for (i = 0; i < sz; i++)
	{
    
    
		printf("% d  ", arr[i]);
	}
	printf("\n");
}
int main()
{
    
    
	int arr[] = {
    
     8,2,3,6,7,9,10 };
	int sz = sizeof(arr) / sizeof(arr[1]);
	//先打印数组
	Print(arr,sz);
	//实现冒泡排序
	BubbleSort(arr, sz);
	Print(arr, sz);
	return 0;
}

结果:

在这里插入图片描述

二、qsort()函数

1. qsort()函数介绍:

函数原型:
在这里插入图片描述

  1. qsort函数是什么类型的数据都可以排序
  2. qsort函数四个参数分别为:base中存放的是待排序数据的首地址,size_t num 表示排序数据元素的个数,size_t size 表示排序数据中每个元素所占大小,比较排序数据的两元素大小的方法(函数)
  3. 使用qsort函数要提供一个你所要比较的两个元素的比较方法
1. 使用qsort排序整型数据
//提供所要比较的两个操作数的比较方法:
int cop_int(const void* e1, const void* e2)
{
    
    
	return *(int*)e1 - *(int*)e2;
}
Print(int arr[], int sz)
{
    
    
	int i = 0;
	for (i = 0; i < sz; i++)
	{
    
    
		printf("% d  ", arr[i]);
	}
	printf("\n");
}
int main() {
    
    
	//整型数据排序
	int arr[10] = {
    
     9,7,6,8,2,1,5,4,3,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//排序
	qsort(arr, sz, sizeof(arr[0]), cop_int);
	//打印
	Print(arr, sz);
	return 0;
}

结果:

在这里插入图片描述

2. 使用qsort函数来排序结构体数据
//定义结构体类型
struct Stu {
    
    
	char name[20];
	int age;
};
//①编写年龄比较的方式函数
int sort_age(void* e1, void* e2) 
{
    
    
	//先把无类型指针e1强制转换成结构体指针
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
//②编写名字比较方式的函数
int sort_name(void* e1, void* e2) 
{
    
    
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

void test_2() {
    
    
	//使用qsort来排序结构体数据
	//初始化结构体
	struct Stu s[3] = {
    
     {
    
    "zhangsan",50},{
    
    "lisi",30},{
    
    "wangwu",20} };
	//计算结构体的大小
	int sz = sizeof(s) / sizeof(s[0]);
	//①按照年龄来排序
	qsort(s, sz, sizeof(s[0]), sort_age);
	//②按照名字来排序
	qsort(s, sz, sizeof(s[0]), sort_name);
}
int main() {
    
    
	test_2();
	return 0;
}

运行结果:

  1. 按照年龄排序:在这里插入图片描述
  2. 按照姓名排序:在这里插入图片描述

2.进阶

2.1 自己编写函数模仿qsort函数的通用算法
//编写交换元素的函数
void Swap(char* buf1, char* buf2, int width) {
    
    
	int i = 0;
	for (i = 0; i < width; i++) {
    
    
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}
//分析:我们交换时,是每一个字节的数据相交换,直到把这个元素所占的字节数都交换;

void imitate_qsort(void* base, int sz, int width, int (*compare)(const void* e1, const void* e2))
{
    
    
	int i = 0;
	//排序的趟数
	for (i = 0; i < sz - 1; i++)
	{
    
    
		int j = 0;//定义每趟要排几个
		for (j = 0; j < sz - 1 - i; j++)
		{
    
    
			//两个元素比较,因为我们不知道具体要比较啥类型数据
			//所有我们要接收一个用户自己编写的比较函数的地址,然后调用这个函数完成排序;
			if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
    
    
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
				//因为我们知道char类型数据在内存中只占一个字节
				// 所以我们把定义的无类型指针base强制转换成char*
				// 之后base*每次就可以一个字节的访问数据
				// 然后,我们又收到了用户所要比较的数据中每个元素的大小sz
				// 所以当我们拿已经知道起始地址的base*,加上元素的大小,这就可以访问每个元素了;
				//交换元素,调用交换函数
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/m0_46569169/article/details/124768470