当前位置:   article > 正文

C语言排序:冒泡排序 , qsort函数_qsort冒泡排序

qsort冒泡排序

目录

一,冒泡排序

1.1冒泡排序思想

1.2 代码实现

二,qsort()函数

2.1 qsort函数的概念

2.2 qsort函数的使用

2.2.1 qsort数组排序

2.2.2 qsort排序结构体

三,模拟实现qsort(采用冒泡的方式)


前言

        这篇文章中你能学习到冒泡排序的思想,以及它的实现方式。了解到qsort()函数的使用,以及怎么用冒泡排序的实现模拟实现qsort()函数。这篇文章需要掌握一定的指针知识,如果有不够熟悉指针的朋友可以看看我往期指针的文章,有助于加深理解。

一,冒泡排序

1.1冒泡排序思想

        对一个无序数组的第一个元素的位置开始,进行两两比较,根据大小交换位置,直到最后将最大 (小)的数交换到了无序队列的队尾,第一趟结束后,第二趟依旧从第一个元素开始排起排到倒数第二个元素结束,第三趟排到到数第三个元素结束,依次类推。

为什么第二趟要到倒数第二个结束,第三个要到倒数第三个元素结束呢?

因为每一趟排序就会把最大(小)值就会放在序列的最后,所以第一趟排完,最大(小)值就已经在最后了。

//这里使用冒泡排序排一组无序数列(降序)
  3    5    4    7    1    8    9    2    0    6
先从第一个数 3 开始,与下一个数比较大小,不满足条件,换位置,接着与下一个数继续比较,直到交换的队尾
 5    3    4    7    1    8    9    2    0    6 

//这里为了满足降序3 和 5交换
 5    4    3    7    1    8    9    2    0    6

//接着,3与下一位继续比较
 5    4    7    3    1    8    9    2    0    6

......

//第一趟排完

5   4     7   3     8    9     2    1    6    0

//第二趟

5   4     7    3     9    8     2    1   6    0

5    4    7    3     9    8      2    6   1   0

//第三趟,第四趟.......第九趟。

一个有n个元素的序列,需要排n-1趟。

1.2 代码实现

  1. #include<stdio.h>
  2. //bubble_sort
  3. void bubble_sort(int arr[10], int sz)
  4. {
  5. int i = 0;
  6. for (i = 0; i < sz - 1; i++) //总共遍历sz-1
  7. {
  8. int j = 0;
  9. for (j = 0; j < sz - i - 1; j++)//每趟进行比较
  10. {
  11. if (arr[j] < arr[j + 1]) //两两比较小的数放后面
  12. {
  13. int tmp = arr[j + 1];
  14. arr[j + 1] = arr[j];
  15. arr[j] = tmp;
  16. }
  17. }
  18. }
  19. for (i = 0; i < sz; i++) //排完打印
  20. {
  21. printf("%d ", arr[i]);
  22. }
  23. return 0;
  24. }
  25. int main()
  26. {
  27. int arr[10] = { 5,4,7,3,1,8,9,2,0,6 };
  28. int sz = sizeof(arr) / sizeof(arr[0]);//元素的个数
  29. bubble_sort(arr, sz);
  30. return 0;
  31. }

二,qsort()函数

冒泡排序只能排序整型数组,而qsort函数非常灵活,能帮助我们排序不同类型的数组元素。

2.1 qsort函数的概念

函数声明:

void  qsort  (void* base,size_t num ,size_t size ,

                                int ( * compar)(const void*e1 ,const void*e2) );

//头文件:stdlib.h

        void* base 表示数组的起始位置,类型是 void*,size_t num 表示数组的元素个数,类型是unsigned int,size_t size表示的是一个元素的大小,单位是字节,后面的函数指针是指向两元素比较的函数,e1和e2是相比较的两元素的地址。

这里的指针的类型是void*,可以接受任意类型的地址。但是要注意两点:

1,void*指针不能直接解引用,需强制类型转换再解引用。

2,void*指针不能直接加减。

2.2 qsort函数的使用

2.2.1 qsort数组排序

例如一个对整型数组进行升序排列,那么比较函数为:

int  cmp_int( const void* e1, const void* e2)

{

        return *( int* ) e1 - *( int* )e 2;

}

例如一个对一个字符型数组进行升序排列(按照ASCII值),那么比较函数为:

int cmp_char( const void* e1, const void* e2)

{

        return *(char*)e2 - *(char*) e2;

}

  1. //qsor排序整型数组(升序)
  2. #include<stdlib.h>
  3. int cmp_int(const void* e1, const void* e2)
  4. {
  5. return *(int*)e1 - *(int*)e2;
  6. }
  7. int main()
  8. {
  9. int arr[10] = { 5,4,7,3,1,8,9,2,0,6 };
  10. int sz = sizeof(arr) / sizeof(arr[0]);//元素的个数
  11. qsort(arr, sz, sizeof(arr[0]),cmp_int);
  12. int i = 0;
  13. for (i = 0; i < sz; i++) //排完打印
  14. {
  15. printf("%d ", arr[i]);
  16. }
  17. return 0;
  18. }

2.2.2 qsort排序结构体

用qsort排序结构体,可以按照结构体里的任意元素排列。

例如:一个结构体里包含名字,年龄。如果分别按照年龄,名字排,那么比较函数分别为:

int  cmp_stu_by_age(const void*e1,const void*e2)        

{

        return ((struct stu*)e1)->age - ((struct stu*)e2 )->age;//按照年龄排

}

int cmp_stu_by_age(const void*e1,const void*e2)

{

        return  strcmp(((struct stu*)e1)->name-((struct stu*)e2) ->name);//利用strcmp函数来比较名字

}

  1. //qsort比较结构体
  2. struct stu
  3. {
  4. char name[10];
  5. int age;
  6. char sex[10];
  7. };
  8. int cmp_age(const void* e1, const void* e2)
  9. {
  10. return ((struct stu*)e1)->age - ((struct stu*)e2)->age; //通过年龄比较
  11. }
  12. int main()
  13. {
  14. struct stu s[3] = { {"张三",20,"男"},{"李四", 32,"男"},{"王五",23,"女"} };
  15. int sz = sizeof(s) / sizeof(s[0]);
  16. qsort(s, sz, sizeof(s[0]), cmp_age);
  17. int i = 0;
  18. for (i = 0; i < sz; i++)
  19. {
  20. printf("%s %d %s \n", s[i].name, s[i].age, s[i].sex);
  21. }
  22. return 0;
  23. }

三,模拟实现qsort(采用冒泡的方式)

        我们还创建一个无序数组来举例,构造bubble()函数排序,bubble接受的参数与qsort一样。但函数内部实现的过程用冒泡的方式来实现。

  1. #include<stdio.h>
  2. void swap(void* e1, void* e2, int size)
  3. {
  4. int i = 0;
  5. for (i = 0; i < size; i++) //一个字节一个字节的交换。。
  6. {
  7. char tmp = 0;
  8. tmp = *((char*)e1+i); //加i是用来换下个字节来相加
  9. *((char*)e1+i) = *((char*)e2+i);
  10. *((char*)e2+i) = tmp;
  11. }
  12. }
  13. void bubble(void* base, size_t num, size_t size, int (*cmp)(const void*, const void*))
  14. {
  15. int i = 0;
  16. for (i = 0; i < num - 1; i++) //num-1趟
  17. {
  18. int j = 0;
  19. for (j = 0; j < num - i - 1; j++)//一趟的过程
  20. {
  21. if (cmp((char*)base + j * size ,(char*)base + (j+1) * size )>0) //将地址转换为char*然后加上比较类型的大小乘以j,
  22. //用来与下一个类型的数比较
  23. {
  24. swap((char*)base + j * size, (char*)base + (j + 1) * size, size); //将待交换的地址作为函数参数
  25. }
  26. }
  27. }
  28. }
  29. int int_cmp(const void* e1, const void* e2) //整型比较函数
  30. {
  31. return *(int*)e1 - *(int*)e2;
  32. }
  33. int main()
  34. {
  35. int arr[] = { 1,3,5,7,9,2,4,6,8,0 };
  36. //char *arr[] = {"aaaa","dddd","ccccc","bbbb"};
  37. int i = 0;
  38. bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), int_cmp); //模拟实现qsort
  39. for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) //打印
  40. {
  41. printf("%d ",arr[i]);
  42. }
  43. return 0;
  44. }

如果需要比较字符型,结构体,只需要把整型比较函数换成对应的比较函数即可。

这上面的整型比较函数int_cmp()其实也是回调函数。

        回调函数是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

        回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

好了,到这里就结束了,希望对大家有所帮助!

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号