qsort()函数实现的是c语言库的快排功能,由于额外空间的处理,相比自己写的更为优化。
注释:自己写的快排由于额外空间冗余,实际运行时会出现超出限制的报错。
一、 一维
qsort调用所包含的头文件 & 函数原型:
#include <stdlib.h>
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 (compar)(const void,const void*)是需要使用者去完成的一个比较函数,即比较器。
比较函数的返回值:
return value | meaning |
---|---|
<0 | The element pointed to by p1 goes before the element pointed to by p2 |
0 | The element pointed to by p1 is equivalent to the element pointed to by p2 |
>0 | The element pointed to by p1 goes after the element pointed to by p2 |
1.qsort函数实现int型排序
int int_cmp(const void * p1, const void p2){
return (( int *)p1 - *(int *) p2);
}
2.对 char 类型的数组排序
int char_cmp(const void* str1, const void* str2){
return (char)str1 - (char)str2;
}
3.对 double 类型数组排序(需要特别注意)
int double_cmp(const void* arr1, const void* arr2){
return (double)arr1 > (double)arr2 ? 1 : -1;
//注意这里是用比较大小的方法,来返回正负
}
4.对结构体一级排序
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 typedef struct Student
5 {
6 int x;
7 int y;
8 //按照x从小到大排序,当x相等时按照y从大到小排序
9 }Student;
10
11 Student student[7];
12
13 int cmp(const void *a, const void *b)
14 {
15 Student* pa1 = (Student*)a;
16 Student* pa2 = (Student*)b;
17
18 return (pa1->x) > (pa2->x) ? 1 : -1;
19 }
20
21 //展示一下对于结构体里赋值的后的结果
22 void Display()
23 {
24 for (int i = 0; i < 7; ++i)
25 {
26 printf("%d\n",student[i].x);
27 }
28 }
29
30 int main()
31 {
32 int arr[7] = { 1,3,5,2,6,9,7 };
33 for (int i = 0; i < 7; ++i)
34 {
35 //将数组arr中的元素赋值给结构体x中
36 student[i].x = arr[i];
37 }
38 Display();
39 qsort(student, 7, sizeof(Student), cmp);
40 for (int i = 0; i < 7; ++i)
41 {
42 printf("%d", student[i].x);
43 }
44
45 return 0;
46 }
5.对机构体二级的排序
就对于4中的结构体来说,如果给x赋值,则x中的值都为0,那么就需要来比较y中的数组。
则可以将代码改为下面这样:
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 typedef struct Student
5 {
6 int x;
7 int y;
8 //按照x从小到大排序,当x相等时按照y从大到小排序
9 }Student;
10
11 Student student[7];
12
13 int cmp(const void *a, const void *b)
14 {
15 Student* pa1 = (Student*)a;
16 Student* pa2 = (Student*)b;
17
18 if (pa1->x != pa2->x)
19 {
20 return (pa1->x) > (pa2->x) ? 1 : -1;
21 }
22 else
23 {
24 return (pa1->y) > (pa2->y) ? 1 : -1;
25 }
26 }
27
28 //展示一下对于结构体里赋值的后的结果
29 void Display()
30 {
31 printf("x=");
32 for (int i = 0; i < 7; ++i)
33 {
34 printf("%d", student[i].x);
35 }
36 printf("\n");
37 printf("y=");
38 for (int i = 0; i < 7; ++i)
39 {
40 printf("%d", student[i].y);
41 }
42 printf("\n");
43 }
44
45 int main()
46 {
47 int arr[7] = { 1,3,5,2,6,9,7 };
48 for (int i = 0; i < 7; ++i)
49 {
50 //将数组arr中的元素赋值给结构体x中
51 student[i].y = arr[i];
52 }
53 Display();
54 printf("排序结构体中的y:\n");
55 qsort(student, 7, sizeof(Student), cmp);
56 for (int i = 0; i < 7; ++i)
57 {
58 printf("%d", student[i].y);
59 }
60
61 return 0;
62 }
6.模仿qsort的功能实现一个通用的冒泡排序
1 //用回调函数模拟实现qsort(冒泡排序的方式)
2
3 #include <stdio.h>
4
5 int int_cmp(const void * p1, const void * p2)
6 {
7 return (*(int *)p1 > *(int *)p2);
8 }
9
10 void _swap(void *p1, void * p2, int size)
11 {
12 int i = 0;
13 for (i = 0; i < size; i++)
14 {
15 char tmp = *((char *)p1 + i);
16 *((char *)p1 + i) = *((char *)p2 + i);
17 *((char *)p2 + i) = tmp;
18 }
19 }
20
21 void bubble(void *base, int count, int size, int(*cmp)(void *, void *))
22 {
23 int i = 0;
24 int j = 0;
25 for (i = 0; i < count - 1; i++)
26 {
27 for (j = 0; j < count - i - 1; j++)
28 {
29 if (cmp((char *)base + j * size, (char *)base + (j + 1)*size) > 0)
30 {
31 _swap((char *)base + j * size, (char *)base + (j + 1)*size, size);
32 }
33 }
34 }
35 }
36 int main() {
37 int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
38 //char *arr[] = {"aaaa","dddd","cccc","bbbb"};
39 int i = 0;
40 bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
41 for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
42 {
43 printf( "%d ", arr[i]);
44 }
45 printf("\n");
46 return 0;
47 }
二、多维
对于malloc
动态申请的多维数组(指针数组)
以一个例子解析:
要求——
打算操作一个数组,数组的每个元素是一个指针,指向2个元素的数组。元素的大小关系为先比较第一个元素,第一个元素相同比较第二个元素。
- 首先,通过
malloc
对指针数组进行分配:
先分配一个指向元素为int *
的一维数组,所以数组类型为int **
; - 然后,针对每一个数组里的
int *
型指针,分配一个一维数组,数组类型为int。
int *b,**a;
a = (int**)malloc(500000*sizeof(int*)); //这里是对int*来分配。
for(i=0;i<500000;i++)
{
b = malloc(2*sizeof(int));
a[i] = b;
}
//这样申请的数组,不是直接free(a),而是如下释放方式:
for(i=0;i<n;i++) { //因为malloc和free要一一对应
free(a[i]);
}
排序用法:
qsort(a, n, sizeof(a[0]), cmp);
qsort的cmp的写法:
入参实际是数组元素的指针,这里元素是int*
,所以入参应该是int**
,而要比较的数组是这个指针指向的内容。
将void* a
强制转型为本来的样子int **
,然后ap指针指向a的第一个元素(这个元素也是指针,指向一个int型一维数组);
int cmp(const void *a,const void *b)
{
int *ap = *(int **)a;
int *bp = *(int **)b;
if(ap[0] == bp[0])
return ap[1] - bp[1];
else
return ap[0] - bp[0];
}
对于非malloc
申请的多维数组
比如:二维数组 int a[5][2];
要求:按照二维数组每一维的第一个元素排序。
比较算法cmp:
int cmp(const void *a, const void *b)
{
return ((int *)a)[0] - ((int *)b)[0];
}
结构体
结构体排序相对简单。
例如——
结构体的结构:
typedef struct node{
int x;
int y;
int z;
}Node;
比较算法cmp,切记强制转型不如 ->
优先级高:
int cmp(const void *a, const void *b)
{
// return (Node *)a->x - (Node *)b->x; //错误写法!
// return ((Node *)a)->x - ((Node *)b)->x; //正确写法1
return (*(Node *)a).x - (*(Node *)b).x; //正确写法2
}