排序方法有很多种:选择排序,冒泡排序,归并排序,快速排序等。快速排序是目前公认的一种比较好的排序算法。因为他速度很快,所以系统也在库里实现了这个算法,便于我们的使用。 这就是qsort函数(全称quicksort)。它是ANSI C标准中提供的,其声明在stdlib.h文件中,是根据二分法写的,其时间复杂度为n*log(n)

功能: 使用快速排序例程进行排序

头文件:stdlib.h

函数原型: void qsort(void* base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*));

参数说明

base:待排序数组,排序之后的结果仍放在这个数组中

num: 数组中待排序元素数量

width: 各元素的占用空间大小(单位为字节)

compare: 指向函数的指针,用于确定排序的顺序(需要用户自定义一个子函数)

函数返回值:无

注意:如果两个元素的值是相同的,那么它们的前后顺序是不确定的。也就是说qsort()是一个不稳定的排序算法。

compar参数详细规则

compar参数是一个函数指针,指向一个比较两个元素的函数。比较函数的原型应该像下面这样。注意两个形参必须是const void *型。另外,因为qsort( )内部在调用compar 函数(compar实质为函数指针,这里称它所指向的函数也为compar)时,传入的实参也已经转换成const void *型,所以在compar函数内部必须将const void *型转换成待排序数组的实际类型,见下文。


int cmp(const void *p1, const void *p2);


如果cmp返回值小于0(< 0),那么p1所指向元素会被排在p2所指向元素的前面

如果cmp返回值等于0(= 0),那么p1所指向元素与p2所指向元素的顺序不确定

如果cmp返回值大于0(> 0),那么p1所指向元素会被排在p2所指向元素的后面

 所以,实现cmp函数时,谨记:

如果满足某个条件时,p1元素应在p2元素前面,那么此时返回负数,比如-1;

如果满足某个条件时,p1元素应在p2元素后面,那么此时返回正数,比如1;

如果满足某个条件时,p1元素和p2元素顺序不影响,那么返回0.(这个时候一般是表示p1==p2)

使用qsort()函数的例子


1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<time.h>
4 #include<string.h>
5 typedef struct
6 {
7 int No;
8 int yuWen,shuXue,yingYu,zongFen;
9 }stu;
10 typedef struct
11 {
12 int x,y;
13 }point;
14
15 //----------随机数相关子函数-----------------------------
16 int getRandomInt(int a,int b)//返回[a,b]之间一个随机整数
17 { return (rand() % (b-a+1))+ a; }
18 double getRandomDouble()//返回0~1之间随机浮点数
19 { return rand()/double(RAND_MAX); }
20 char getUpChar()//返回随机大写字母
21 { return ((char)(rand()%26+'A')); }
22 char getDownChar()//返回随机小写字母
23 { return ((char)(rand()%26+'a')); }
24 void InitRandom()
25 { srand((unsigned)time(0)); }
26 //-------------------------------------------------------
27
28
29 int cmp1(const void *a,const void *b)//int数组从小到大排序
30 { return *(int*)a -*(int*)b; }
31 int cmp2(const void *a,const void *b)//int数组从大到小排序
32 { return *(int*)b -*(int*)a; }
33
34 /*在对浮点或者double型的数据比较时一定要用三目运算符,
35 因为要是使用像整型那样相减的话,如果是两个很接近的数,
36 则可能返回一个很小的小数(大于-1,小于1),而cmp的返
37 回值是int型,因此会将这个小数返回0,系统认为是相等,
38 失去了本来存在的大小关系 */
39 int cmp3(const void *a,const void *b)//double数组从小到大排序
40 {
41 //return *(double*)a -*(double*)b;//这种写法比较危险。因为无法直接判定两个浮点数相等。
42 return *(double *)a > *(double *)b ? 1 : -1;
43 }
44
45 int cmp4(const void *a,const void *b)//char数组从小到大排序
46 { return *(char*)a -*(char*)b; }
47
48 int cmp5(const void *a,const void *b)//对字符串数组排序
49 {
50 char *x=(char*)a;
51 char *y=(char*)b;
52 return strcmp(x,y);
53 }
54
55 int cmp6(const void *a,const void *b)//对stu结构体类型数组排序
56 {//优先按总分从大到小,总分相等则按学号从小到大
57 stu x=*(stu*)a;
58 stu y=*(stu*)b;
59 if(x.zongFen<y.zongFen)return 1;
60 else if(x.zongFen>y.zongFen) return -1;
61 else
62 {
63 if(x.No<y.No)return -1;//返回负数-1表示参数一应该排在参数二前面
64 else if(x.No>y.No) return 1;//返回正数1表示参数一应该排在参数二后面
65 else return 0;//返回0表示参数一和参数二相等,最终排序结果中,两者的顺序不确定。
66 }
67 }
68 int cmp7(const void *a,const void *b)//对point结构体类型数组元素排序
69 { //优先按x从小到大排序,当x相等则按y从大到小排序。
70 point *p1=(point*)a;
71 point *p2=(point*)b;
72 if(p1->x < p2->x) return -1;//返回负数-1表示参数一应该排在参数二前面
73 else if(p1->x > p2->x)return 1;//返回正数1表示参数一应该排在参数二后面
74 else
75 {
76 if(p1->y > p2->y)return -1;
77 else if(p1->y < p2->y)return 1;
78 else return 0;//返回0表示参数一和参数二相等,最终排序结果中,两者的顺序不确定。
79 }
80 }
81
82 int main()
83 {
84 int IntArr[15],IntArr2[15],IntArr3[15],i,n=15;
85 double dArr[15];
86 char cArr[15];
87 char strArr[100][100];//每行一个字符串
88 stu stuArr[50];//每个元素表示一个学生的数据
89 point pArr[50];//每个元素表示一个整数点的数据(x,y)
90 InitRandom();
91 //-------------------------------------------------------
92 for(i=0;i<n;i++)//生成随机整数数组
93 {
94 IntArr3[i]=IntArr2[i]=IntArr[i]=getRandomInt(1,1000);
95 printf("%d ",IntArr[i]);
96 }
97 printf("\n");
98 //-------------------------------------------------------
99 qsort(IntArr,n,sizeof(IntArr[0]),cmp1);//int[]从小到大排序
100 for(i=0;i<n;i++)
101 printf("%d ",IntArr[i]);
102 printf("\n");
103 //-------------------------------------------------------
104 qsort(IntArr2,n,sizeof(IntArr2[0]),cmp2);//int[]从大到小排序
105 for(i=0;i<n;i++)
106 printf("%d ",IntArr2[i]);
107 printf("\n");
108 //-------------------------------------------------------
109 qsort(IntArr3+1,n-1,sizeof(IntArr3[1]),cmp2);//int[]从大到小排序,第0号元素不参与排序
110 for(i=0;i<n;i++)
111 printf("%d ",IntArr3[i]);
112 printf("\n\n\n");
113
114
115
116 //-------------------------------------------------------
117 n=10;
118 for(i=0;i<n;i++)//生成随机浮点数数组
119 {
120 dArr[i]=getRandomDouble()*1000;
121 printf("%.2lf ",dArr[i]);
122 }
123 printf("\n");
124 //-------------------------------------------------------
125 qsort(dArr,n,sizeof(dArr[0]),cmp3);//double[]从小到大排序
126 for(i=0;i<n;i++)
127 printf("%.2lf ",dArr[i]);
128 printf("\n\n\n");
129 //-------------------------------------------------------
130
131
132
133
134 //-------------------------------------------------------
135 n=15;
136 for(i=0;i<n;i++)//生成随机字符数组
137 {
138 cArr[i]=getUpChar();
139 printf("%c ",cArr[i]);
140 }
141 printf("\n");
142 //-------------------------------------------------------
143 qsort(cArr,n,sizeof(cArr[0]),cmp4);//char[]从小到大排序
144 for(i=0;i<n;i++)
145 printf("%c ",cArr[i]);
146 printf("\n\n\n");
147 //-------------------------------------------------------
148
149
150
151
152 //-------------------------------------------------------
153 n=10;
154 for(i=0;i<n;i++)//生成随机字符串数组
155 {
156 int len=getRandomInt(5,15);
157 for(int j=0;j<len;j++)
158 strArr[i][j]=getDownChar();
159 strArr[i][len]='\0';
160 printf("%s\n",strArr[i]);
161 }
162 printf("\n");
163 //-------------------------------------------------------
164 qsort(strArr,n,sizeof(strArr[0]),cmp5);//字符串数组从小到大排序
165 for(i=0;i<n;i++)
166 printf("%s\n",strArr[i]);
167 printf("\n\n\n");
168 //-------------------------------------------------------
169
170
171
172 //-------------------------------------------------------
173 n=10;
174 for(i=0;i<n;i++)//生成stu结构体类型的随机数据
175 {
176 stuArr[i].No=1000+i;
177 stuArr[i].yuWen=getRandomInt(90,150);
178 stuArr[i].shuXue=getRandomInt(90,150);
179 stuArr[i].yingYu=getRandomInt(90,150);
180 stuArr[i].zongFen=stuArr[i].yuWen+stuArr[i].shuXue+stuArr[i].yingYu;
181 printf("%d %3d %3d %3d %3d\n",stuArr[i].No,stuArr[i].yuWen,stuArr[i].shuXue,stuArr[i].yingYu,stuArr[i].zongFen);
182 }
183 printf("\n");
184 //-------------------------------------------------------
185 qsort(stuArr,n,sizeof(stuArr[0]),cmp6);//对stu类型数组排序
186 for(i=0;i<n;i++)
187 printf("%d %3d %3d %3d %3d\n",stuArr[i].No,stuArr[i].yuWen,stuArr[i].shuXue,stuArr[i].yingYu,stuArr[i].zongFen);
188 printf("\n\n\n");
189 //-------------------------------------------------------
190
191
192
193 //-------------------------------------------------------
194 n=10;
195 for(i=0;i<n;i++)//生成point结构体类型的随机数据
196 {
197 pArr[i].x=getRandomInt(80,100);
198 pArr[i].y=getRandomInt(1,100);
199 printf("%2d %2d\n",pArr[i].x,pArr[i].y);
200 }
201 printf("\n");
202 //-------------------------------------------------------
203 qsort(pArr,n,sizeof(pArr[0]),cmp7);//对point类型数组排序
204 for(i=0;i<n;i++)
205 printf("%2d %2d\n",pArr[i].x,pArr[i].y);
206 printf("\n\n\n");
207
208
209
210
211 return 0;
212 }