使用冒泡排序模拟qsort

目录

冒泡排序:

冒泡排序特点:

模拟&改造:

1、让冒泡排序能够接受其他的数据类型,使用参数的改造。

2、比较的方式进行改造❤

思路分析:

 3、交换的代码需要改造‍

 cmp的回调:

️‍最终代码演示: 


冒泡排序:

http://t.csdn.cn/HQfDO      

冒泡排序特点:

1、利用数组中的元素进行俩两比较,和循环的多次遍历进行排序,得到一个升序或者降序的排列顺序。


2、但是效率过于底下,以及通过qsort的对比,冒泡排序只能用于整型(int)数组的比较和排列,对于其他数据类型的数组比较,显得无能为力。


3、而且,效率底下,运算需要进行多次的遍历,需要设定另外的变量值,进行急刹车,才能避免不必要的遍历循环。

模拟&改造:

1、让冒泡排序能够接受其他的数据类型,使用参数的改造。

  • int arr[] ——void*base  利用void*接收任意类型的地址
  • int sz ——size_t sz  因为void* 所以要有sz进行元素大小的判定,以便接下来移动指针
  • 增加 size_t width   因为void* 所以要有width得知每个元素的字节大小,以便接下来移动指针
  • 增加int(*cmp)(const void*,constvoid*) 使用comaprt 进行函数回调,一次进行两个元素之间的大小比较
void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void*el, const void*e2))

2、比较的方式进行改造❤

原先的比较方式:if (arr[j] > arr[j + 1])


  • 原本的比较方式是基于整型数组的原理上,进行前后元素的比较。 
  • 现在,数据的类型发生了改变,变成了void*这种通用类型。
  • 站在程序员的角度,程序员是不明白用户在传输时究竟是哪一种的数据类型,所以不能直接指定某一种数据类型进行比较
  • 这是一个 if  语句,而compart的判断原理是两个数字之间的比较返值。 
  • 需要交换的条件究竟是什么?是需要升序?还是需要降序?

 使用冒泡排序模拟qsort_第1张图片

if(cmp((char*)base+j*width,(char*)base +(j+1)*width) > 0)

思路分析:


if(cmp()>0) 其实是利用了cmp的返回值原理   

  • return(前一个元素   减    后一个元素)
  • 返回值大于0 则表示前一个元素大于后一个元素
  • 返回值小于0 则表示前一个元素小于后一个元素
  • 返回值等于0 则表示两个元素的数值是相等的

♥♥(char*)base+j*width  

  •     前文说过,站在程序员的角度,我们是不知晓用户传输的数据类型,但是对于char*来说有一个特有的优势。
  •     char*在进行访问字节的过程中,char*base+1 是只能访问一个字节的,而相对于其他,列如:int*base+1 是一次访问了四个字节。
  •     对于char*一次只能访问一个字节的特点,我们可以利用width以及下标 j 相结合组合成一个适合char*能够从首元素地址出发,指向某个元素的地址,的运算方式。

使用冒泡排序模拟qsort_第2张图片

 使用冒泡排序模拟qsort_第3张图片

 3、交换的代码需要改造‍


原先交换的代码:

                              int tmp = arr[j];

                              arr[j] = arr[j + i];

                              arr[j + 1] = tmp;


  • 原先交换的代码是基于整型数组的原理上进行的。
  • 交换时,我们的指针类型是否需要进行改变?若不需要进行再次的转变,那么该如何进行交换?
Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);

在面对交换问题的同时,为了简化或是说将整个代码进行简洁化,我们采用了函数调用的方式,以此解决问题。 

void Swap(char* buf1, char* buf2, size_t width)
{
   int i = 0;
   for (i = 0; i < width; i++)//利用遍历,进行字节和字节之间的交换
   {
      char tmp = *bufl;
      *buf1 = *buf2;
      *buf2 = tmp;
      buf1++:
      buf2++;
   }

}

 还是引用前文的话,站在程序员的角度,我们无法知晓用户传输的数据类型究竟是什么,所以在此处无法进行数据类型的转化,所以还是使用char*进行交换。


而char*在前文也有提过,是char*base+1只能访问一个字节,所以我们可以利用循环的遍历,将宽度作为循环的最大次数,以此来进行字节和字节之间的交换,直到抵达相对应的字节大小(宽度)。

使用冒泡排序模拟qsort_第4张图片

 cmp的回调:

int cmp(const void* e1, const void* e2)
{
   return *(int*)el - *(int*)e2;
}
  •  因为,cmp 在 qsor的 int  (*cmp)(const void*,const void*) 以及 在前文的 if 判定返值中必须是int整型类型的。
  • 也同时,cmp 是单独独立的一个函数调用,是独立的函数,进行修改时,并不会涉及其他函数的使用,所以此处便可直接进行指针数据类型的转化。
  • 最后,如果要更换数据类型进行比较,也只需要修改主函数的内容和cmp的回调内容即可。

️‍最终代码演示: 

void Swap(char* buf1, char* buf2, size_t width)//交换
{
	int i = 0;
	for (i = 0; i < width; i++)//利用遍历,进行字节和字节之间的交换
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}

}
void BB(void* base, size_t sz, size_t width, int(*cmp)(const void*, const void*))//冒泡排模拟qsort
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)//i表示排序的趟数,和冒泡排序一样的意思
	{
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)//j表示下摆,和冒泡排序一样的意思
		{
			if (cmp((char*)base + j * width,(char*)base + (j + 1) * width) > 0)//接收返回值
			{
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

int cmp(const void*e1 , const void* e2)//进行返回值
{
	return *(int*)e1 - *(int*)e2;
}
void print(int* arr, int sz)//打印
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
void test1()
{
	int arr[] = { 3,1,5,2,4,8,7,9,10,11,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	BB(arr, sz, sizeof(arr[0]), cmp);//进行比较的函数,cmp回调
	print(arr, sz);//打印数组
}
int main()
{
	test1();
	return 0;
}

使用冒泡排序模拟qsort_第5张图片

你可能感兴趣的:(C语言,c语言,指针,函数,算法)