赞
踩
目录
我们之前学过的冒泡排序只能进行对整数类型的排序,冒泡排序代码如下:
- void BubbleSort(int array[],int len)
- {
- int tem;
- //外层循环控制 排序的趟数 n个元素排序需要循环n-1次
- for(int i=0;i<len-1;i++)
- {
- //内层循环控制比较的次数 n个元素第i趟比较n-i次
- for(int j=0;j<len-1-i;j++)
- {
- //比较相邻的元素大小 目的:将最大的元素选出到移动到最后
- if(array[j]>array[j+1])
- {
- tem = array[j];
- array[j] = array[j+1];
- array[j+1] = tem;
- }
- }
- }
- }
上述冒泡排序的代码中,其整型的比较方式为“array[j]>array[j+1]”,但如果换一种数据类型很明显再使用上述方法比较两个元素是错误的。而我们今天要学习的qsort函数就能解决元素类型不同(注:两个相互比较的元素类型必须相同)而引起的问题。其使用的算法思想为:快速排序
我们先来看看qsort函数参数分别代表什么意思:(下图截至MSDN)
由于第四个参数是比较函数,需要我们自己编写,根据比较元素类型的不同编写不同的比较函数。
在写这个代码之前我们先来学习一个知识点:void* — 无类型指针 — 接收任意类型变量的地址
char ch = ‘w’;
void* p = &ch; //不会报错
所以为了能够接收任意类型地址,使用void*更合适。
错误的使用:
char ch = ‘w’;
void* p = &ch;
*p = ‘s’; //报错
由于void* 是无(具体)类型的指针,而解引用时不知到访问几个字节,因此void* 类型的指针是不能进行解引用的,同理也不能进行+1整数的操作。
理解了void* 的内容就容易理解设计qsort函数时为什么使用void* 来接收了。
根据上面所说的参数含义我们先使用案例来为大家讲解qsort函数的使用:
使用qsort排序数组:arr[10] = { 9,8,7,6,5,4,3,2,1}
- #include <stdio.h>
- #include<stdlib.h>
- int cmp_int(const void* e1, const void* e2) //接收要比较两个元素的地址
- {
- //比较两个整型值的函数
- return *(int*)e1 - *(int*)e2;
- }
- int main()
- {
- int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
- int sz = sizeof(arr) / sizeof(arr[0]);
- qsort(arr, sz, sizeof(arr[0]), cmp_int);
-
- return 0;
- }
代码分析:
运行结果如下(上面代码漏了打印语句):
有了前面的基础,在后面的类型中的使用大同小异(仅仅是在比较函数中,类型不同元素之间的比较方式不同),不做过多叙述。
我们再来看看浮点型的比较:
使用qsort排序数组:arr[10] = { 9.1,8.5,7.5,6.7,5.1,4.4,3.1,2.3,1.1}
代码如下:(不含主函数)
- int cmp_float(const void* e1, const void* e2) //接收要比较两个元素的地址
- {
- //比较两个浮点型值的函数
- if (*(int*)e1 == *(int*)e2)
- {
- return 0;
- }
- else if (*(int*)e1 < *(int*)e2)
- {
- return -1;
- }
- else if (*(int*)e1 > *(int*)e2)
- {
- return 1;
- }
- }
由于函数的返回类型为int,而两个浮点型相减结果为浮点型,因此需要进行一些处理,不能直接return。若想直接return可以最后进行强制类型转换为int
由于结构体是一个复杂的数据类型,所以需要通过里面一种元素进行比较。
使用qsort排序下面的结构体:
struct Stu
{
char name[20];
int age;
};struct Stu s[3] = { {"zhangsan",20},{"lisi",30},{"wangwu",10} };
1)根据年龄比较
- #include <stdio.h>
- #include<stdlib.h>
- struct Stu
- {
- char name[20];
- int age;
- };
-
- int cmp_stu_by_age(const void* e1, const void* e2)
- {
- return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
- }
-
- int main()
- {
- struct Stu s[3] = { {"zhangsan",20},{"lisi",30},{"wangwu",10} };
- int sz = sizeof(s) / sizeof(s[0]);
- qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
-
- for (int i = 0; i < 3; i++)
- {
- printf("%s %d\n", s[i].name, s[i].age);
- }
- return 0;
- }
由于年龄是int类型的变量,只需要将e1与e2转换成结构体类型,再访问年龄相减即可。
2)根据名字比较
- #include <stdio.h>
- #include<stdlib.h>
- #include<string.h>
- struct Stu
- {
- char name[20];
- int age;
- };
-
- int cmp_stu_by_name(const void* e1, const void* e2)
- {
- return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
- }
-
- int main()
- {
- struct Stu s[3] = { {"zhangsan",20},{"lisi",30},{"wangwu",10} };
- int sz = sizeof(s) / sizeof(s[0]);
- qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
-
- for (int i = 0; i < 3; i++)
- {
- printf("%s %d\n", s[i].name, s[i].age);
- }
- return 0;
- }
比较名字就是比较字符串,字符串比较不能直接使用 > < =直接比较,应该使用strcmp函数。
- #include <stdio.h>
- int int_cmp(const void* p1, const void* p2)
- {
- return (*(int*)p1 - *(int*)p2);
- }
- void _swap(void* p1, void* p2, int size)
- {
- int i = 0;
- for (i = 0; i < size; i++)
- {
- char tmp = *((char*)p1 + i);
- *((char*)p1 + i) = *((char*)p2 + i);
- *((char*)p2 + i) = tmp;
- }
- }
-
- void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
- {
- int i = 0;
- int j = 0;
- for (i = 0; i < count - 1; i++)
- {
- for (j = 0; j < count - i - 1; j++)
- {
- if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
- {
- _swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
- }
- }
- }
- }
- int main()
- {
- int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
- int i = 0;
- bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
- for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
- {
- printf("%d ", arr[i]);
- }
- printf("\n");
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。