冒泡排序,qsort的使用与构造

1.冒泡排序

对数据排序的方式有很多

冒泡排序

选择排序

插入排序

快速排序

。。。

qsort是回调函数的案例

qosrt—是一个库函数,底层使用的快速排序的方式来对数据进行排序

这个函数可以直接使用(#include<stdlib.h>)

这个函数可以用来排序任意类型的数据

1.1冒泡排序的思想

冒泡排序的思想,两两相邻的元素进行比较

#include<stdio.h>



void bubble_sort(int arr[],int sz)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tem = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tem;
			}
		}

	}
}
void print(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[] = { 1,3,4,6,7,8,9,2,5,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(arr, sz);
	bubble_sort(arr,sz);
	print(arr,sz);


	return 0;
}

一组数据,两两相比,如果前面的大于后面的数就进行交换(升序),那么我们要对假如10个数据来进行比较,我们先让一个数与后面的进行比较,假设这个数是最大的,我们需要多少比几组呢?

答:是10-1组;这样走一趟后我们还剩下9个数,这九个数再一次向后比较,一共需要多少趟呢?

答:是9趟;那么我们每走完一趟,之前的那个数就会比如说10,已经是最大的了就不需要比较了,那么每次比一趟,我们比的次数就会减一。

void bubble_sort(int arr[],int sz)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)//冒泡排序的趟数
	{
		for (j = 0; j < sz - 1 - i; j++)//一趟冒泡排序
		{
			if (arr[j] > arr[j + 1])
			{
				int tem = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tem;
			}
		}

	}
}

2.qsort库函数的使用方法

qsort是一个库函数,头文件使用是#include<stdlib.h>

是quick sort 的缩写(快排)。

我们可以打开网站,然后点击legacy version,搜索qsortcplusplus.comicon-default.png?t=N7T8https://cplusplus.com/

我们可以看到如下界面,里面描述,qsort函数需要的参数

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

2.1void* 类型介绍

我们之前学到,每一种数据类型都有相对应的类型指针,如char类型是char*指针

int类型是int*指针;那么void*是什么意思呢?

答:void*类似一个垃圾站可以接收任意类型的指针。

void*的性质:1.void*可以接收任意的指针;2.void*不能解引用(因为他不是任何类型,我们解引用不知道读取几个字节的数据)

qsort库函数,是可以处理任意类型的函数,他接收指针类型也必须是任意类型所以用到了void*。

2.2qosrt函数的使用

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

 我们首先看到了

1.void*base 告诉我们需要一个,

需要排序数组的第一个元素的指针

2.size_t num告诉我们需要一个,

这个数组的元素个数

3.size_t size告诉我们需要一个,

这个数组每一个元素的大小

4. int (*comper)(const void*,const void*)这个的意思是,

要我们自己给出一个可以比较数组中元素的函数,并把函数的指针传过来(因为我们要进行比较的内容只有我们自己知道,计算机并不能直接读取)。并且这个函数的返回类型是int 而且函数的参数是2个void*。

下面我们来使用这个函数:

int main()
{
	int arr[10] = { 5,4,2,1,3,0,9,8,7,6 };//我们先使用比较简单的数据,一个乱序的整形数组
	int sum = sizeof(arr) / sizeof(arr[0]);//我们得到他的元素个数
	int size = sizeof(arr[0]);             //我们得到他每个元素的大小
	qsort(arr, sum, sizeof(arr[0]),?);     
//依次填入:数组开始的地址(也就是数组名)
//数组元素个数
//数组的元素大小
//比较数组中2个元素的函数?
	return 0;
}

上面的代码里我们已经填入了要求我们的数据,那么还有一个函数该怎么写呢?

这里我们明确知道的是比较两个整形,整形数据该怎么比较呢?

函数的参数是两个void*该怎么比较呢?

我们一一来解决

函数的参数是两个void*该怎么比较呢?答:

我们的比较函数并不是要真实的传入2个数据,而是对某一种类型进行比较,所以我们可以对void*进行强制类型转换把其转换为(int*),再对其解引用。

我们来写这个简单的函数

int cmp_int(const void* e1, const void*e2)
{
	return *(int*)e1 - *(int*)e2;
}

这样我们就可以轻松使用了;

3.模拟实现qsort

摸拟原码如下:

#include<string.h>
#include<stdio.h>
struct stu
{
	char name[20];
	int age;
};
void swp( char* e1, char* e2 ,int sz)//交换函数,我们不能确定比较2个数据的大小,因为我们传入的类型是char*,所以我们需要再传入一个数据大小的参数
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		char tmp = *e1;
		*e1 = *e2;
		*e2 = tmp;
		e1++;
		e2++;
	}
}

	//一个首元素的指针  //这个数组的元素个数
void qsort(void* base, size_t sum, size_t size, int (*cmp)(const void* e1, const void* e2))		//qsort函数,底层逻辑是冒泡排序
{								//	这数组每个元素的大小		//需要使用者自己设计一个比较元素大小的函数,并传给这个函数指针
	int i = 0;
	for (i = 0; i < sum - 1; i++)//冒泡排序的每一趟
	{
		int j = 0;
		for (j = 0; j < sum - 1 - i; j++)//冒泡排序,每一趟的每一对的交换
		{	
			//      因为这个函数开头要求了一个判断函数指针,所以我们直接使用就好了
			//不管你什么类型,传过去都改为char*类型的指针,因为我们要适配所有类型;
			//改成char*类型的好处就是,我们还知道数据的大小,就可以跳过该数据的大小来进行比较
			//就可以比较任意类型的数据了
			if (cmp((char*)base + size * j, (char*)base + size * (j+1)) > 0)
			{
				swp((char*)base + size * j, (char*)base + size * (j + 1), size);//因为我们不知道这个类型,并且我们强制转换成为了char类型,如果大于这个类型,我们该怎么办?
				//所以我们交换的时候,要把这个类型大小加进去 这样我们再把这一个类型范围内所有数据都交换
				//

			}
		}
	}

}

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


int cmp_int(const void* e1, const void*e2)//e1是一个指针,存放了要比较元素的地址
{                                         //e2是一个指针,存放了要比较元素的地址
	return *(int*)e1 - *(int*)e2;
}

int cmp_age(const void* e1, const void* e2)
{
	return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
int cmp_name(const void* e1, const void* e2)
{
	return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}



void test1()
{
	int arr[10] = { 5,4,2,1,3,0,9,8,7,6 };
	int sum = sizeof(arr) / sizeof(arr[0]);
	int size = sizeof(arr[0]);
	print(arr,sum);
	qsort(arr, sum, sizeof(arr[0]), cmp_int);
	print(arr,sum);
}

void test2()
{
	struct stu arry[3] = { {"zhang",14},{"li",11},{"ma",10} };
	int sum2 = sizeof(arry) / sizeof(arry[0]);
	int size2 = sizeof(arry[0]);
	qsort(arry, sum2, sizeof(arry[0]), cmp_name);
}

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

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
冒泡排序和快速排序(qsort)虽然都是常见的排序算法,但它们的工作原理和效率有很大的不同。冒泡排序是一种简单的比较排序算法,而快速排序则是一种高效的分治策略。如果你想了解如何模仿`qsort`实现冒泡排序,其实这不是一个直接的对应,因为`qsort`是基于分治法的高效排序,而冒泡排序更适合教学和理解基本排序原理。 不过,为了满足你的要求,我们可以探讨一下如何用类似`qsort`的方式设计一个冒泡排序的“迭代”版本,虽然这并不是真正意义上的模仿,因为它们在实现上并不相同。 **冒泡排序的简化版(不是真正的`qsort`)**: 1. 定义一个辅助函数,类似于`qsort`的分区过程,但仅用于比较相邻元素并交换: ```c++ void bubbleSortPartition(int arr[], int low, int high) { while (low < high) { if (arr[low] > arr[high]) { std::swap(arr[low], arr[high]); } low++; high--; } } ``` 2. 用递归调用的方式实现冒泡排序: ```c++ void bubbleSortIterative(int arr[], int size) { for (int i = 0; i < size - 1; i++) { bubbleSortPartition(arr, 0, size - 1 - i); } } ``` 这里我们不是直接将整个数组作为一次排序,而是每次缩小待排序范围,直到整个序列有序。 **相关问题--:** 1. 冒泡排序与快速排序的主要区别是什么? 2. 在冒泡排序中,为什么要使用`bubbleSortPartition`函数? 3. 如何评价这种将冒泡排序与`qsort`风格结合的简化版本?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值