冒泡排序
#include <stdio.h>
void bubble_sort(int*, int);
int main()
{
int arr[5] = { 99, 45, 78, 55, 23 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
void bubble_sort(int* arr, int n)
{
int i = 0;
for(i = 0; i < n - 1; i++)
{
int j = 0;
for (j = 0; j < n - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
在bubble_sort函数中,n代表数组的长度,外层的循环变量是 i ,代表遍历数组的次数,在数组长度为 n 的情况下,会遍历 n-1 次,i 从 0 开始,i 的取值范围是 [0, n-1)。内层循环变量是 j ,因为每次循环都可以把最后一个元素的值确定,所以 j 的值在每次遍历完一遍数组后都会减 1 ,也就是说 j 的取值与 i 的取值相关, i 的取值是[0, n - 1), 所以 j 的取值是[0, n - 1 - i),每次对 arr[ j ] 和 arr[ j + 1 ]进行比较,满足条件的进行交换。
在这个冒泡排序中,我们只能对 int 类型的数组进行排序,而不能对其它类型的元素进行排序。
qsort函数
void qsort( void *base, size_t num, size_t width, int (*compare )(const void *elem1, const void *elem2 ) );
如果要使用qsort函数,需要引用头文件<stdlib.h>,qsort函数可以对任意类型的数据进行排序,但qsort函数在使用时需要自定义一个函数compare,通过该函数的返回值来确定是否进行交换,和上面冒泡排序中的判断 arr[ j ] 和 arr[ j + 1 ] 的大小来决定是否交换类似。
对qsort函数感兴趣的可以点击这个链接: qsort函数
模拟实现
如果想要通过冒泡排序来进行对任意元素的排序,就需要像qsort函数那样,假设对需要排序的数组一无所知,我们需要获取该数组的起始地址,起始地址的类型设置成void*, 我们还需要获取数组的元素个数,该参数可以设置成 int (个数不会为负数,可以选择unsigned int,也就是qsort函数的size_t ),还需要知道每个元素的大小,才能知道下一个元素的起始地址,可以设置成 int 类型,此外,我们还需要一个compare函数,这个函数由用户自己设计,该函数的返回值应该为 int 类型,如果返回值大于0,进行相邻两个元素的交换,该函数的两个参数应该是数组中两个相邻元素的起始地址。
bubble_sort函数
对刚才的冒泡排序函数进行修改,就可以得到可以交换任何数据的冒泡排序函数。通过给出的数据,可以计算出相邻的两个元素的起始地址分别是,arr + width * j 和 arr + width * (j + 1) ,将两个元素的起始地址传到compare函数中进行数据的计算,通过返回值判断是否对这两个元素进行交换。
void bubble_qsort(const void* arr, int num, int width, int(*p)(void*, void*))
{
int i = 0;
int j = 0;
for (i = 0; i < num - 1; i++)
{
for (j = 0; j < num - 1 - i; j++)
{
if (p((char*)arr + width * j, (char*)arr + width * (j + 1)) > 0)
{
swap((char*)arr + width * j, (char*)arr + width * (j + 1), width);
}
}
}
}
swap函数
因为char类型只占一个字节,所以可以将传来的两个地址强制类型转换为char*,因为要对两个元素进行交换,所以要交换所有字节,还需要知道每个元素占的字节数,所以还需要传个 int 类型的变量来保存字节数。
void swap(char* n1, char* n2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char temp = *(n1 + i);
*(n1 + i) = *(n2 + i);
*(n2 + i) = temp;
}
}
compare函数
compare函数是用户自定义的函数,用户是知道数据的类型的,所以可以先将数据进行相应的类型转换,然后对转换后的数据进行计算,如果第一个元素大于第二个,返回值为正;如果第一个元素小于第二个元素,返回值为负。
因为返回值是int类型的,所以对于int类型的变量,可以返回两个变量相减的结果;对于double类型,需要对两个变量的大小进行比较;对于字符串类型,可以直接使用strcmp()作为返回值。
int int_cmp(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
int cmp_age(const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int cmp_name(const void* e1, const void* e2)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int cmp_double(const void* e1, const void* e2)
{
return *(double*)e1 > *(double*)e2 ? 1 : 0;
}
代码示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int int_cmp(const void*, const void*);
int cmp_age(const void*, const void*);
int cmp_name(const void*, const void*);
int cmp_double(const void*, const void*);
void bubble_qsort(const void*, int, int, int(*)(void*, void*));
void swap(char*, char*, int);
struct Stu
{
int age;
char name[4];
};
int main()
{
int arr[10] = { 2, 4, 1, 9, 7, 8, 6, 5, 10, 3 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
double arr1[10] = {2.4, 9.8, 5.6, 8.7, 3.3, 99.4, 56.4, 21.9, 42.5, 15.6};
int len = sizeof(arr1) / sizeof(arr1[0]);
bubble_qsort(arr1, len, sizeof(arr1[0]), cmp_double);
bubble_qsort(arr, sz, sizeof arr[0], int_cmp);
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
putchar('\n');
for (i = 0; i < len; i++)
{
printf("%.1f ", arr1[i]);
}
printf("\n");
struct Stu s1 = { 20, "Tom" };
struct Stu s2 = { 115, "Ac" };
struct Stu s3 = { 99, "Ji" };
struct Stu s[3] = { s1, s2, s3 };
int num = sizeof(s) / sizeof(s[0]);
bubble_qsort(s, num, sizeof(s[0]), cmp_age);
for (i = 0; i < num; i++)
{
printf("%d ", s[i].age);
}
printf("\n");
bubble_qsort(s, num, sizeof(s[0]), cmp_name);
for (i = 0; i < num; i++)
{
printf("%s ", s[i].name);
}
return 0;
}
int int_cmp(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
int cmp_age(const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int cmp_name(const void* e1, const void* e2)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int cmp_double(const void* e1, const void* e2)
{
return *(double*)e1 > *(double*)e2 ? 1 : 0;
}
void bubble_qsort(const void* arr, int num, int width, int(*p)(void*, void*))
{
int i = 0;
int j = 0;
for (i = 0; i < num - 1; i++)
{
for (j = 0; j < num - 1 - i; j++)
{
if (p((char*)arr + width * j, (char*)arr + width * (j + 1)) > 0)
{
swap((char*)arr + width * j, (char*)arr + width * (j + 1), width);
}
}
}
}
void swap(char* n1, char* n2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char temp = *(n1 + i);
*(n1 + i) = *(n2 + i);
*(n2 + i) = temp;
}
}
运行结果图: