冒泡排序简单来说就是相邻两数字进行比较,谁大排后面,比较完之后就得到了有序的数组
例如
我有一个待排的数字序列:3 5 8 10 2
第一次比较 3 5 8 2 10
第二次比较 3 5 2 8 10
第三次比较 3 2 5 8 10
第四次比较 2 3 5 8 10
由此我们可以知道,你的序列有几个,比较的次数是序列-1
那么我们的代码如下
#include <stdio.h>
void BubbleSort(int arr[], int sz)
{
int i = 0;
int j = 0;
int tmp = 0;
int flag = 1;//防止数组已经有序排列却还要进行比较的现象发生
for ( i = 0; i < sz-1; i++)//排序次数等于数组总数减一
{
for (j = 0; j < sz - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;
}
}
if (flag)
break;
}
}
int main()
{
int arr[] = { 8,3,2,5,9,10,11 };
int sz = sizeof(arr) / sizeof(arr[0]);//获取数组有几个元素
int i = 0;
BubbleSort(arr, sz);
for ( i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
但我们这个代码是有缺点的,就是它只能比较整型的数字,因此我们可以使用C语言自带的qsort函数来进行排序,我们可以看qsort的详细介绍
这个是它的声明
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
我们可以发现这个函数需要四个形参
第一个形参需要接收的是指针,意思是该函数要数组的首元素地址
第二个参数是数组元素的个数
第三个参数是每个元素的大小,以字节为单位
第四个参数是函数指针,这是要我们自己写一个能比较两个元素大小的函数,然后把函数的地址传给这个形参。
代码如下
#include <stdio.h>
int compare(const void* e1, const void* e2)
{
return (*(int*)e1 - *(int*)e2);
}
int main()
{
int arr[] = { 8,3,2,5,9,10,11 };
int i = 0;
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), compare);
for ( i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
compare函数中的e1和e2都是指针,指向一个整数,通过它们指向的地址所存放的数字进行比较,返回它们相差的值。一般我们的指针都是有特定的类型的,比如int*,char*。但我们这里是放了void*,这是无具体类型的指针,能够接收任意类型的地址。但不能进行计算,不能加减整数,也不能解引用,因此我们要强制转换成int*类型进行运算。
qsort不仅能用于整数排序,也可以用在字符、浮点数、结构体等排序
以字符和结构体的为例
接下来是字符的
#include <stdio.h>
/*字符比较的是ascii码的大小*/
int char_compare(const void* e1, const void* e2)
{
return *(char*)e1 - *(char*)e2;
}
int main()
{
char arr[] = "hello";
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz - 1, sizeof(arr[0]), char_compare);
//因为字符串有\0因此减1
printf("%s", arr);
return 0;
}
接下来是结构体的
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Stu
{
char name[20];
int age;
};
int point_compare_by_name(const void* e1, const void* e2)
{
strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int point_compare_by_age(const void* e1, const void* e2)
{
return (((struct Stu*)e1)->age) - (((struct Stu*)e2)->age);
}
int main()
{
int i = 0;
struct Stu s[] = {{"zhangsan",15},{"lisi",30},{"wangwu",25}};
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), point_compare_by_name);
for ( i = 0; i < sz; i++)
{
printf("%s %d\n", s[i].name, s[i].age);
}
qsort(s, sz, sizeof(s[0]), point_compare_by_age);
for (i = 0; i < sz; i++)
{
printf("%s %d\n", s[i].name, s[i].age);
}
return 0;
}
接下来我们用冒泡排序去模拟qsort
代码如下
#include <stdio.h>
#include <stdlib.h>
//void Swap(const void* e1, const void* e2,int width)//char写法
//{
// char tmp = 0;//最好写char跟后面的对应
// int i = 0;
// for ( i = 0; i < width; i++)
// {
// tmp = *((char*)e1 + i);
// *((char*)e1 + i) = *((char*)e2 + i);
// *((char*)e2 + i) = tmp;
// }
//}
void Swap(const void* e1, const void* e2, int sz)//int写法
{
int tmp = 0;
int i = 0;
tmp = *((int*)e1);
*((int*)e1) = *((int*)e2);
*((int*)e2) = tmp;
}
int compare(const void* e1, const void* e2)
{
return (*(int*)e1 - *(int*)e2);
}
void BubbleSort(void* base, int sz, int width, int (*compare)(const void*, const void*))
{
int i = 0;
int j = 0;
for ( i = 0; i < sz; i++)
{
for (j = 0; j < sz - 1 - i; j++)
{
/*if (compare((char*)base + j * width, (char*)base + (j+1) * width) > 0)
{
Swap((char*)base + j * width, (char*)base + (j+1) * width, width);
}*/
if (compare((int*)base + j , (int*)base + (j + 1)) > 0)
{
Swap((int*)base + j, (int*)base + (j + 1), sz);
}
}
}
}
int main()
{
int i = 0;
int arr[] = { 1,7,5,4,9,8,2 };
int sz = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr, sz, sizeof(arr[0]), compare);
for ( i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
因为int能跳四个字节,而char只能跳一个字节,因此有不同的写法。