假设我们现在又是个乱序的数字,10 2 3 4 1 6 8 5 9 7,要对这十个数字进行升序排序(越往右数字越大),我们可以这样子做:
10个数排序,需要比较9躺。推广得到,要排序n个数,需要比较n-1躺。
一下列出每趟要进行的比较次数:
趟数 | 比较次数 |
---|---|
1 | 9 |
2 | 8 |
3 | 7 |
4 | 6 |
5 | 5 |
6 | 4 |
7 | 3 |
8 | 2 |
9 | 1 |
比较次数j与趟数i、数字个数n的关系为:j = n - i
为什么比较次数越来越少呢?
原因很简单,在每进行一趟后,就会有一个数被放在正确的位置(比如本例中,大多数放在右边),而这些以及被放在正确位置的数,我们就不需要再去和他们比较了。
void bubble(int arr[], int sz) // sz为元素个数
{
int i = 0;
for(i=0;i<sz-1;i++) // n-1趟
{
int j = 0;
for(j=0;j<sz-1-i;j++) // 比较
{
if(arr[j]>arr[j+1])
{
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
以上代码存在一些问题:
其实在stdlib.h中有一个函数qsort可以实现上面的功能,在初学时,我们可以参考这些库函数来提高我们的代码水平!
下面是qsort函数的原型:
void qsort (void* base,
size_t num,
size_t size,
int (*compar)(const void*,const void*));
可以看到qsort函数有四个参数,其含义分别是:
参数 | 含义 |
---|---|
base | 待排序数据中第一个对象的地址 |
num | 待排序数据的个数 |
size | 待排序数据的大小(字节) |
( * compar)(const void * ,const void *) | 用来比较待排序数据中的两个元素的函数,需要自己设计 |
使用void*类型,使得可以对数字,字符串,等等各种类型的数据进行排序。
其中最重要的就是最后一个参数,在设计它时,要满足以下要求:
当p1大于p2时,返回大于0的数;
当p1小于p2时,返回小于0的数;
当p1等于p2时,返回0;
且函数原型要满足返回值是int,元素为(const void * ,const void *)
举例子:
int compar_int(const void* a, const void* b)
{
return (*(int *)a) - (*(int*)b);
}
注意:(int*)是必要的,因此a和b都是void *,如果直接解引用,系统不知道他的类型是什么,也就没办法正确从内存中提取正确的字节数的数据。
现在让我们来写一个类似的qsort函数:
函数申明:
void bubble_sort(void* base, int sz, int width, int(*cmp)(const void*e1, const void*e2))
{
int i = 0;
for(i = 0;i < sz - 1;i++) // 一趟
{
int j = 0;
for(j=0;j<sz-1-i;j++)
{
if(cmp(((char*)base+j*width, (char*)base+(j+1)*width))>0)
{
// 交换
Swap((char*)base+j*width,);
}
}
}
}