自从学会了用qsortqsortqsort排序之后,再也没有在程序里自己写排序了。
第一次还觉得这个函数怎么用起来这么复杂,还得自己编写比较函数,现在可不这么觉得了,觉得好用的一批,这个比较函数简直是神器。那么下面就来介绍下qsortqsortqsort函数的使用吧,关键就是 比较函数 的编写。
函数原型:
void qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *));
1、普通简单形式元素:
typedef int TYPE;
int cmp(const void* A, const void* B)
{
return *(TYPE*)A - *(TYPE*)B;
}
TYPE nodes[] = {2, 9, 2, 5, 14, 8, 20};
int n = sizeof(nodes)/sizeof(*nodes);
qsort(nodes, n, sizeof(*nodes), cmp);
排序后原数组变为2, 2, 5, 8, 9, 14, 20
。这里的TYPE是intintint型,当然也可以换成charcharchar, floatfloatfloat, doubledoubledouble等类型,道理一样不再赘述。
2、二维数组中一维数组:
这句话的意思好像怎么看都有点歧义的感觉,那就举个例子来说明吧:
现在有个二维数组,每一行都存储了一个字符串,现在要对这个二维数组中的字符串进行排序,排序之后这个二维数组的每一行的字符串变成有序。比较函数可以这么写:
int cmp(const void* A, const void* B)
{
return strcmp((char*)A, (char*)B);
}
现在令二维数组为:
char nodes[4][10] = {"Hello", "world!", "C", "program"};
其长度为:
int n = sizeof(nodes)/sizeof(*nodes);
随后排序:
qsort(nodes, n, sizeof(*nodes), cmp);
二维数组中的字符串变为升序:
C
Hello
program
world!
3、结构体元素排序
令结构体为:
typedef struct NODE
{
int a;
char str[10];
}Node;
- 如果结构体要针对其中的子元素aaa进行排序,比较函数可以写为:
int cmp(const void* A, const void* B)
{
return (*(Node*)A).a - (*(Node*)B).a;
}
这里一定要注意括号!因为
.
的优先级比*
高
或者用->
一样的,依然要注意括号
int cmp(const void* A, const void* B)
{
return ((Node*)A)->a - ((Node*)B)->a;
}
- 如果对结构体的strstrstr 进行排序,比较函数可写为:
int cmp(const void* A, const void* B)
{
return strcmp((*(Node*)A).str, (*(Node*)B).str)
}
基本的用法也就这样了,如果仅仅是进行以上的简单排序,那么自己写个排序函数好像也没啥难度,不一定非要用qsortqsortqsort。而当比较情况变复杂的时候,qsortqsortqsort函数的优势就体现出来了,这也是它真正吸引我的地方。举个例子吧:
仓库管理员小闻最近进了一批钢管,这批钢管应该按照老板的指示来排放,可是老板的要求有点苛刻:
1.首先按照钢管的编号降序排序
2.编号一样时,按照钢管直径长度升序排序
3.钢管直径也一样,那么按照长度降序排序
这下子可把小闻难坏了,?坑爹的老板。你来帮帮小闻把这批钢管排序吧!
typedef struct STEEL
{
int num;
int diameter;
int lenth;
}Steel;
int cmp(const void* a, const void* b)
{
if((*(Steel*)a).num != (*(stell*)b).num)
return (*(Steel*)b).num - (*(stell*)a).num;//按照序号降序排序
if((*(Steel*)a).diameter != (*(stell*)b).diameter)
return (*(Steel*)a).diameter - (*(stell*)b).diameter;//按照直径升序排序
if((*(Steel*)a).lenth != (*(stell*)b).lenth)
return (*(Steel*)b).lenth - (*(stell*)a).lenth;//按照长度降序排序
return 0;
}
Steel steel[n];
qsort(steel, n, sizeof(*steel), cmp);
假如现在有5个数据:
1 2 3
1 1 5
3 2 1
3 2 3
5 1 1
那么,经排序后,得到:
5 1 1
3 2 3
3 2 1
1 1 5
1 2 3
确实是序号降序,直径升序,长度降序排序。
补充:指针数组的排序
现在有一个指针数组: p={"Where there is hope ,there is a way","Welcome Beijing","Nice idea","Have fun"}
,对这个数组进行排序,比较函数写为:
int cmp(const void* A, const void* B)
{
return strcmp(*(char**)A, *(char**)B);
}
再更:结构体指针数组的排序
2019.2.4
typedef struct NODE{
int num;
struct NODE* next;
}Node;
int cmp(const void* A, const void* B){
return (*(Node**)A)->num - (*(Node**)B)->num;
}
void sort(Node* head){
int top = 0;
int lenth = getLength(head);
Node* buff[lenth];
//目的是将这个链表的所有节点的地址存放起来,然后对这个数组中的指针排序。
//在gdb中调试,可以看到buff的类型为: (Node *(*)[0])
Node* p = head->next;
while(p){
buff[top++] = p;
p = p->next;
}
qsort(buff, lenth, sizeof(*buff), cmp);
p = head;
for(int i = 0; i < lenth; i++){
p->next = buff[i];
p = p->next;
}
p->next = NULL;
}
文末祝大家学习愉快^_^