【C语言】使用冒泡排序思想模拟sqort函数

  【C语言】使用冒泡排序思想模拟sqort函数_第1张图片

 每日壁纸分享(出处: 极简壁纸_海量电脑桌面壁纸美图_4K超高清_最潮壁纸网站)

前言

  qsort 是C语言中的一个库函数,它可以对任意类型的数据进行排序,而它的排序思想是快速排序,今天我将使用冒泡排序的思想来尝试实现。


目录

前言

一,qsort函数

1,qsort使用格式和传参要求

2,qsort函数的使用示例

二,冒泡排序思想

三,使用冒泡排序思想模拟实现qsort函数

1,strcmp函数

2,函数构想

         思路说明:

3,函数实现

函数解析:

  一,bubble_sort函数

  二, compare函数

  三,swap函数



一,qsort函数

  在开始之前,先介绍qsort函数,以便后续使用冒泡排序实现其功能。

1,qsort使用格式和传参要求

  qsort函数是C语言中的一个库函数,使用该函数需要包含头文件

  在www.cplusplus.com 官网中我们可以查阅到该函数的传参格式如下:

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

  可以清楚地看到,使用qsort函数需要传递四个参数:

      第一个:void *base,即是首元素地址,需要使用者将待比较排序数组地第一个元素地址传递过来。使用viod* 接收是因为无法确定使用者会传递什么类型的地址,故使用通用指针类型,可以接收到任意数据类型的地址。

      第二个:size_t num,意为元素个数,需要使用这传递带比较数组的元素个数,建议不要写死元素个数,可以使用 sizeof(arr)/sizeof(arr[0]) 进行传递。

      第三个:size_t size ,意为单个元素所占内存的大小,一般使用sizeof()来求取。第二个和第三个的类型之所以使用size_t 类型,是因为无论是元素个数还是单个元素所占内存大小,这都不可能是负数,故应当使用 unsigned int 类型更为合适。

      第四个:需要传递一个函数用与两个数的比较(就是给出一种比较大小的方式),函数返回类型和参数类型及其个数如下:

int (*compar)(const void*, const void*)

        需要对两个数进行比较:

        当a>b时返回大于零的数字

        当a

        当a=b时返回零

2,qsort函数的使用示例

  理论是较为抽象的,接下来我将使用qsort函数对一组整型数组进行排序,以演示该函数的实现。

#include 
#include 
int compare(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}

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

int main()
{
	//首先将要比较的数放进一个数组中,已乱序
	int arr[] = { 8,9,0,1,2,5,3,4,7,6 };
    //计算元素个数
	int sz = sizeof(arr) / sizeof(arr[0]);
	//排序前打印
	printf("排序前\n");
	print_arr(arr, sz);
	printf("\n");
	//调用qsort函数
	//传参: 首元素地址 元素个数 单个元素所占内存空间大小 比较方式函数
	qsort(arr, sz, sizeof(arr[0]), compare);
	//排序后打印
	printf("排序后\n");
	print_arr(arr, sz);
	return 0;
}

  这里稍微提讲一下 compare函数,我们只需要其提供一种比较方式,使得当a>b时返回大于零的数字,当a

  在上述代码中,因为 compare 函数是以void*的指针类型接收参数,这是无法进行操作的,故我将其强制类型转换为 int*类型并解引用(因为我已知它是对一个整型数组进行排序),这样它就是一个int类型的数,此时使用e1 - e2,即可满足compare函数所需要的比较方式。

  输出结果:

【C语言】使用冒泡排序思想模拟sqort函数_第2张图片

二,冒泡排序思想

   冒泡排序的核⼼思想就是:两两相邻的元素进⾏⽐较。

  代码如下:

#include 

void sort(int* p, int sz)
{
    int i = 0;
    //比较轮次
    for (i = 0; i < sz - 1; i++)//sz是数组元素的个数,10个元素需要比较9次,即是sz-1
    {
        int j = 0;
        int flag = 1;//假定排序完毕
        for (j = 0; j < sz - 1 - i; j++)
//第一轮将第一个元素排好需要sz-1次,而每一轮会减少一个,故j *(p + j + 1))
//当a1>a2就交换,因为前小后大
            {
                int tmp = 0;
                tmp = *(p + j);
                *(p + j) = *(p + j + 1);
                *(p + j + 1) = tmp;
                flag = 0;
            }
        }
        if (flag == 1)
            break;
    }
    return;
}

void print(int* pp, int sz)
{
    int i = 0;
  for (i = 0; i < sz; i++)
   {
      printf("%d ",*(pp+i));
   }
  return;
}

int main()
{
    int arr[15] = {0};
    int i = 0;
    int n = 0;
    for (i = 0; i < 15; i++)
    {
        scanf("%d", &arr[i]);
    }
    int sz = &arr[15] - &arr[0];
    sort(arr,sz);
    print(arr,sz);
    return 0;
}

  由上我们可得到冒泡排序的思想:两层循环嵌套,外层循环为排序n个元素需要循环n-1次;内层循环为两个元素依次比较,若是满足条件便交换,从而实现排序。

三,使用冒泡排序思想模拟实现qsort函数

  前文中我用整型数组演示了qsort函数的使用方式,那么在该函数中我便将字符数组假定为排序对象进行实现。

  1,strcmp函数

  若是要对字符进行排序,则需要引入strcmp函数

  strcmp函数是C语言中的库函数,使用该函数需要包含头文件: 。strcmp函数是专门用来比较字符串大小的,比较方式是按照a,b,c,d...x,y,z 的前后位置来确定。

  strcmp函数格式:

    在www.cplusplus.com 官网中我们可以查阅到该函数的传参格式如下: 

int strcmp ( const char * str1, const char * str2 );

  返回类型如下:

【C语言】使用冒泡排序思想模拟sqort函数_第3张图片

  即是 当a>b时返回大于零的数字,当a这刚好契合compare函数所需要的返回参数。

2,函数构想

    以下为该函数的设计思路:

#include 
#include 
#include 
//排序
void bubble_sort(void* base, size_t sz, size_t width, int compare(const void* e1, const void* e2))
{
	size_t i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		size_t j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (compare() > 0)//通过比较方式得到两个元素的大小关系
			{
				swap();//交换
			}
		}
	}
}
//比较
int compare(const void* e1, const void* e2)
{
//..
}
//交换
void swap()
{
//..
}

int main()
{
	//将所需比较的元素放入数组
	char* ch1 = "department";
	char* ch2 = "complicated";
	char* ch3 = "boom";
	char* ch4=  "astronomer";

	char* arrp[4] = { ch1,ch2,ch3,ch4 };
	int sz = sizeof(arrp) / sizeof(arrp[0]);
	//将冒泡排序实现的函数命名为bubble_sort
	bubble_sort(arrp,sz,sizeof(arrp[0]),compare);
	return 0;
}
  思路说明:

  1,因为是需要使用冒泡排序的思想实现qsort函数,所以对 bubble_sort函数 的传参便需要数组元素个数 sz,以此来实现两两相邻元素依次比较。

  2,因为该函数需要对任意数据类型的排序都能实现,换句话说就是我们不知道使用该函数的人会传递什么数据给 bubble_sort函数 ,所以函数无法使用特定的数据类型去接收,故只能使用void*。而一旦是传递地址给 void* 类型接收,由于void* 无类型大小,由此会导致在后续两个元素交换无法实现,故需要传递单个元素大小 width。

  3,同样的,因为该函数需要对任意数据类型的排序都能实现,而有排序就一定有比较,故比较方式需要使用者自行传入,以 compare 函数接收。

  

3,函数实现

#include 
#include 
#include 
//函数声明
void swap(char* e1, char* e2, int width);
void bubble_sort(void* base, size_t sz, size_t width, int compare(const void* e1, const void* e2));

//排序
void bubble_sort(void* base, size_t sz, size_t width, int compare(const void* e1, const void* e2))
{
	size_t i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		size_t j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
				if (compare((char*)base + (j * width), ((char*)base + ((j + 1) * width))) > 0)
				{
                //当满足条件是调用swap函数进行交换
				swap(((char*)base + (j*width)), ((char*)base + ((j + 1)*width)),width);//交换  
			    }
		}
	}
}
//比较
int compare(const void* e1, const void* e2)
{
	return strcmp(*(char**)e1, *(char**)e2);

}
//交换
void swap (char* e1, char* e2,int width)
{
	//一个字符一个字符进行交换
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *e1;
		*e1 = *e2;
		*e2 = tmp;
		e1++;
		e2++;
	}
}

void print_arrp(char** p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s\n", *(p + i));
	}
}

int main()
{
	//将所需比较的元素放入数组
	char* ch1 = "department";
	char* ch2 = "complicated";	
    char* ch3 = "boom";
	char* ch4=  "astronomer";

	char* arrp[4] = { ch1,ch2,ch3,ch4 };
	int sz = sizeof(arrp) / sizeof(arrp[0]);
	//将冒泡排序实现的函数命名为bubble_sort
	printf("排序前\n");
	print_arrp(arrp, sz);
	printf("\n");
	bubble_sort(arrp,sz,sizeof(arrp[0]),compare);
	printf("排序后\n");
	print_arrp(arrp, sz);
	return 0;
}
   函数解析:
          一,bubble_sort函数

【C语言】使用冒泡排序思想模拟sqort函数_第4张图片

  通过一个嵌套循环实现冒泡排序的两两相邻元素依次比较,元素以compare函数进行比较大小,当满足条件时调用swap函数交换内存。

  这里需要着重讲一下对compare函数与swap函数的传参:

  因为bubble_sort函数接收的是数据类型为 void* 的数组首元素的地址,所以首先要对其进行强制类型转换,这里我们转换的是char*类型,主要的目的是想要使得base加减整数时所操作的内存为一字节。

  我们已经有了base(数组首元素地址),也有width(单个元素所占内存空间大小),同时也设定了 j 来表示数组下标。我们将其强制类型转换为 char* 类型指针,这样就保证其每次加减整数都是操作1字节的空间,我们只需要 (char*)base + j(元素下标)* width(单个元素所占内存空间大小)== 首地址向前推进 j 个 元素所占内存大小空间,也就是指向&arrp[j]的地址!

   当我开始调试后得到base == 0x0055FE04 == &arrp[0] 。

   已知 sizeof(arrp[0]) == 4,即是当j=0时,base向前跳过0字节到达 0x0055FE04 == &arrp[0];当j=1时,base向前跳过4字节到达 0x0055FE08 == &arrp[1];当j=2时,base向前跳过8字节到达 0x0055FE0C == &arrp[2]...

   易知,当我们跳过 j*width 个字节后,地址刚好就指向&arrp[j]的地址,这便是我所这样写的用意。

   

          二, compare函数

【C语言】使用冒泡排序思想模拟sqort函数_第5张图片

   已知我们传参过来的是&arrp[j],这是一个char**类型的指针,但是却使用的void* 类型去接收,故我们需要将其强转为char**类型,又因为strcmp函数需要的的参数是:(const char * str1, const char * str2) ,故对其解引用得:*(char**)e1 == *(&arrp[j]) == arrp[j] == *(arrp + j) == 指针变量ch。

   而strcmp函数的返回值与我们所需的返回值契合,所以该函数直接返回strcmp函数的返回值。

         三,swap函数

【C语言】使用冒泡排序思想模拟sqort函数_第6张图片

  当函数满足判断条件后,便会调用该函数以达到交换的目的。

  已知swap函数所接收的地址是&arrp[j]和&arrp[j+1]这两个地址,因为在传参时我已将这两个指针强转为char*来保证每次加减整数只操作一个字节,同样的在swap函数中我也有同样的需求,所以便直接以char*类型接收。

  又由于我只知道交换字符的起始地址,于是便将width(单个元素所占字节的个数)传递过来,那么swap函数便是从这个地址开始往后交换,一共交换width个字节便结束,此时恰好是一个元素的大小。

【C语言】使用冒泡排序思想模拟sqort函数_第7张图片【C语言】使用冒泡排序思想模拟sqort函数_第8张图片

  如上图所示,所交换的是该地址所指向的地址,也就是所指向的字符串,以此来达到对const类型排序的目的。

本次知识分享到此结束,谢谢大家观看!

你可能感兴趣的:(c语言,开发语言)