水中的气泡会一点点地上浮到水面最后冒出,而这种排序算法的每一个元素都可以像小气泡一样,根据自身大小一点一点向着数组的左侧或者右侧移动。
对于一个无序数组,我们要实现其中的元素按照升序排序或者降序排序,可以使用冒泡排序这种最基础的排序方法。
先介绍一下冒泡排序的思路(以升序为例,数组元素个数为n):
- 从数组的第一个元素开始比较与后面元素的大小。如果第一个元素比第二个元素大,就交换他们两个。
- 然后对第二个元素重复上面的操作,如果第二个元素比第三个元素大,就交换他们两个。
- 一直重复这种操作,直到第n-1个元素和第n个元素比较完成。这样,数组最右边的元素也就是第n个元素一定是数组中最大的。
- 然后重复1-3的过程,只不过这次比较的元素只有n-1个,因为最大的元素已经在第3步到达数组最右边了。这样依次得到n-1个元素,n-2个元素。。。
下面用画图的方式来演示一下思路(以1-10一共10个元素的数组为例):
上面是第一趟排序,一共交换9次,我们将最大的元素10放到了最左边(下标为9),同样的方法进行第二趟排序,一共交换8次,将第二大的元素9放到10的右边(下标为8),直到第9趟排序完成后,得到最终的升序数组1 2 3 4 5 6 7 8 9 10
从上面的思路中不难看出来,要排序n个元素的数组就得排序n-1趟,第i趟则要交换n-i次
通过这个思路,代码实现就很容易了,我们将这个冒泡排序的程序写成函数:
#include <stdio.h>
void bubble_sort(int arr[], int sz)//传入数组和数组元素的个数sz
{
int i;
for (i = 1; i <= sz - 1; i++)//趟数
{
int j = 0;
for (j = 1; j <= sz - i; j++)//交换的个数
{
if (arr[j-1] > arr[j])//交换两个元素
{
int tmp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = tmp;
}
}
}
}
int main()
{
int i;
int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr,sz);
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
值得注意的是:在数组那一章强调过,由于函数中传入的数组名只是数组的首元素地址,因此我们不能在函数中对数组求大小(求sz),必须在函数外求出sz的大小再传入函数中。
另外,由于数组的下标是从0开始,这也就意为着第n个元素的下标是n-1,因此在交换的时候第i个元素,它的下标实际上是第i-1;为了方便我们还是将j的循环条件从0开始,这样就符合数组下标的特性了,同理趟数也要从0开始。
这样的话for循环的条件则要进行修改,for (i = 0; i < sz - 1; i++)
,因为从0开始,要循环sz-1趟的条件是i < sz - 1
,如果是 i <= sz - 1
则会循环sz次;同理交换次数的循环也要改成for (j = 0; j < sz - i - 1; j++)
,因为i
和j
从0开始,j <= sz - i
也要改成 j < sz - i - 1
所以,最终的代码是下面这样:
#include <stdio.h>
void bubble_sort(int arr[], int sz)//传入数组和数组元素的个数sz
{
int i;
for (i = 0; i < sz - 1; i++)//趟数
{
int j = 0;
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;
}
}
}
}
int main()
{
int i;
int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr,sz);
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
上面是升序排列的方法,至于降序排列,只需要把交换的条件中的大于改成小于即可。