最近不少朋友可能被排序的问题所困扰,特别是我们常见的两大基本排序问题:冒泡排序,选择排序;在这里我将会和简单介绍一下冒泡排序和选择排序的使用,然后详细讲解一下qsort快速排序;
1.冒泡排序
2.选择排序
3.qsort快排
(1)qsort函数的函数库及其所调用参数,返回类型
(2)各个参数的解释:
void *base
size_t num
size_t width
int (__cdecl *compare )(const void *elem1, const void *elem2 )
话不多说,进入正题:
1,冒泡排序:
我们先举个例子:输入5名学生成绩存放一维数组,用冒泡排序从小到大,输出原始成绩和排序后成绩。(从小到大输出)
#include<stdio.h>
#define N 5
void Bubblesort(int arr[], int sz)
{
int i = 0;
int j = 0;
for (i = 0; i < sz - 1; i++)
{
for (j = 0; j < sz - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
printf("排序后成绩:\n");
for (i = 0; i < sz; i++)
printf("%d ", arr[i]);
printf("\n");
}
int main()
{
int i;
int arr[N];
printf("请输入%d名学生成绩:\n",N);
for (i = 0; i < N; i++)
{
scanf("%d", &arr[i]);
}
printf("原始成绩:\n");
for (i = 0; i < N; i++)printf("%d ", arr[i]); printf("\n");
int sz = sizeof(arr) / sizeof(arr[0]);
Bubblesort(arr, sz);
return 0;
}
即有5个元素的数组我们假设为56,65,67,76,78,冒泡排序就是类似于两两比较,定义两个循环变量i(控制比较的趟数),j(一趟比较的次数)进入冒泡排序(因为每一趟我们可以选择一个最大的数,最后两个数比较时,一个确定为最大,那另一个也就自然而然地确定了,所以我们需要比较9趟),一开始进入第一趟(i=0),第一次arr[0]与arr[1]比较,如果前者大于后者,则两者互换位置,否则,两者不互换;比较后,进入第二次比较,由于每次比较结束后j都会自增,所以第二次为arr[1]与arr[2]比较,如此往复;我们第一趟比较完后会在最后选择出最大值78。进入第二趟(i=1)因为上一躺我们已经选择出最大值78,所以第二趟比较的时候就不用再与最后的那个78参与比较了(因为78已经是最大值再次比较也不会改变他的位置,多余的比较只会影响计算机的运行速度),所以第二趟我们需要比较的次数就是sz-i-1(sz总元素个数,sz-1比较的第一躺两两比较的次数;sz-1-i第i行比较的次数(eg:第一行我们需要比较4次)),然后第二行两两比较如此往复......我们就实现了冒泡排序,截下来我们只要将数组的值用一个循环输出就ok了。
2,选择法:斯~(本人不太喜欢选择法)
同样的,我们回到上一个例子:输入5名学生成绩存放一维数组,用冒泡排序从小到大,输出原始成绩和排序后成绩。(从小到大输出)
#include<stdio.h>
#define N 5
void Selectsort(int arr[])
{
int i, j,k;
for (i = 0; i < N-1; i++)
{
k = i;
for (j = i+1; j <N; j++)
{
if (arr[k]> arr[j])k=j;//选择最小的数
}
int tmp = arr[i];
arr[i] = arr[k];
arr[k] = tmp;//将最小的数于前面的数交换
}
printf("排序后成绩:\n");
for (i = 0; i <N; i++)
printf("%d ", arr[i]);
printf("\n");
}
int main()
{
int i;
int arr[N];
printf("请输入%d名学生成绩:\n", N);
for (i = 0; i < N; i++)
{
scanf("%d", &arr[i]);
}
printf("原始成绩:\n");
for (i = 0; i < N; i++)
printf("%d ", arr[i]);
printf("\n");
Selectsort(arr);
return 0;
}
选择法最主要是先在数组元素中选择最小的元素,将其与第一个元素互换一下位置。第一次比较我们要比较四次,我们先保留i原数据的值,定义一个k,k赋值为i,让arr[k]与arr[j]比较,选择出最小的值56再与arr[0]互换位置。然后第二次我们的选择范围会缩短(减少计算机运算时间,因为arr[0]我们已经确定为最小值,所以再次比较位置也不会变化)然后我们除去56再选择最小的值65与arr[1]互换位置,如此往复...便完成选择。我们只需在最后输出即可。(个人观点(可忽略):对我个人,这个算法我几乎不用,但考虑到各位朋友可能会有些疑惑,我只好被迫加班咯)
怎么说呢,最近各位都在为冒泡和选择排序的过程太繁琐而苦恼着,我就和大家介绍一下另一种函数(不知道朋友们的老师讲不讲,反正我的老师目前没讲)好了,开始吧!
(1)qsort(Quick Sort)即快速排序;我们所谓的冒泡排序,选择排序一般适用于数字之间的比较未免有些局限,而我们这里的qsort不仅可以是数字,字符串,结构体都可以用qsort进行比较,该函数返回类型为空,即不需要返回值,当我们使用参数时我们需要引用函数库stdlib即#include<stdlib.h>即可;
(2)我们看看数里面的参数:
第一个参数为void*base即首元素地址,因为qsort函数比较的类型很多,所以上面显示的为void*类型,而当我们真正用的时候,我们需要将其改成我们的带比较元素类型;
第二个参数为 size_t num即我们待比较元素的个数,举个例子,如果我们的比较的是arr[5]那么这里填写的就是5,但习惯我们用sizeof求个数;
(3)第三个size_t width元素宽度即每个元素的大小(单位:字节);类似的,我们也习惯用sizeof来求解;
(4)这也是大家困惑最多的地方,比较函数,在这里是比较函数的函数地址,该函数两个参数,都是void类型,因为每个类型都不太相同,所以我们需要有一个统一的标准即全部强制转化为char*,这就完美的体现了(3)的作用,可以完美的使指针指向下一个元素,当然这是qsort函数内部应该解决的,和我们使用者没有关系,我们只需要严格的按照规定输入即可;
cmp函数有返回类型,为int(这个也是确定的,不能更改),这是我们严格按照模板输入的,我们用e1-e2计算cmp的返回值,当返回值<0,则e1在前,>0时,则e2在前;
所以关于上面的例题,我们有如下解法:
#include<stdio.h>
#include<stdlib.h>
#define N 10
int cmp(const void* e1, const void* e2)//比较函数
{
int* a = (int*)e1;
int*b = (int*)e2;
return (*a - *b);
}
int main()
{
int i = 0;
int arr[N];
printf("请输入%d个数字:\n",N);
for (i = 0; i < N; i++)
scanf("%d",&arr[i]);
printf("原始成绩:\n");
for (i = 0; i < N; i++)
printf("%d ", arr[i]); printf("\n");
qsort(arr,N, sizeof(arr[0]),cmp);//快排实现
printf("排序后成绩:\n");//输出
for (i = 0; i <N; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
这就避免了冒泡排序与选择排序的繁琐,是一个值得学习的新函数,好啦,感兴趣大家可以多多研究,就这样咯,拜啦