排序算法-3-冒泡排序

冒泡排序

前面讲了插入排序选择排序,下面说另一种也很容易想到的排序方法:冒泡排序。

原理

冒泡排序的基本原理是通过不断交换相邻的两个元素来让小的元素越来越靠前,大的元素越来越靠后,就像轻的气泡往上浮一样。步骤如下:假设有n个元素,

  • 先考虑内层循环。
  1. 比较第一个和第二个元素,若第一个大,则交换,否则不交换;
  2. 比较第二个和第三个元素,若第二个大,则交换,否则不交换;
  3. 比较第三个和第四个元素,若第三个大,则交换,否则不交换;
  4. 以此类推,直到最后一个元素。

    这样经过内层循环一遍之后,最大的元素会被交换到最后。

  • 再考虑外层循环。外层循环的每一次,内层循环会走一遍。第一遍的时候内层循环要走到第n个元素,第一遍走完,第二遍的时候就只需要走到第(n-1)个元素即可,以此类推,最后一遍只需要走到第二个元素。

要注意冒泡排序与选择排序的区别,两者都会在内循环中把最小/大的元素找出来,但冒泡排序是通过不断交换相邻的元素,而选择排序是选出最小/大的元素然后跟最前/后面的交换;冒泡排序一次内循环之后除了找出来最小/大的元素以外,其他的元素也有可能变化,会消除一些逆序,而选择排序只会改变最小/大的元素和最前/后面的元素。

实现

按照这个原理我们来用代码实现。这时问题又来了:是否可以像插入排序选择排序一样,也不需要另外开辟空间,直接在原址上排序呢?答案同样是可以。因为只需要两个元素的交换操作,不需要额外的空间。

下面就是用C语言实现的代码。

  • 要排序的数组a有n个元素。
  • 外层循环进行n-1次,每次会把还未排序的元素a[0...i]中的最大的元素沉到a[i]的位置。
void bubble_sort(int a[], int n)
{
    if(n<=0)
        return;

    int i,j,tmp;
    for(i=n-1;i>0;i--) {
        for(j=0;j<i;j++) {
            if(a[j]>a[j+1]) {
                tmp = a[j];
                a[j]= a[j+1];
                a[j+1] = tmp;
            }
        }
    }
}

为了验证此函数的效果,加上了如下辅助代码,对3个数组进行排序,运行结果在最后,可见排序成功。

#include <stdio.h>
#include <stdlib.h>

#define SIZE_ARRAY_1 5
#define SIZE_ARRAY_2 6
#define SIZE_ARRAY_3 20

void bubble_sort(int a[], int n);
void show_array(int a[], int n);

void main()
{
    int array1[SIZE_ARRAY_1]={1,4,2,-9,0};
    int array2[SIZE_ARRAY_2]={10,5,2,1,9,2};
    int array3[SIZE_ARRAY_3];

    for(int i=0; i<SIZE_ARRAY_3; i++) {
        array3[i] = (int)((40.0*rand())/(RAND_MAX+1.0)-20);
    }

    printf("Before sort, ");
    show_array(array1, SIZE_ARRAY_1);
    bubble_sort(array1, SIZE_ARRAY_1);
    printf("After sort, ");
    show_array(array1, SIZE_ARRAY_1);

    printf("Before sort, ");
    show_array(array2, SIZE_ARRAY_2);
    bubble_sort(array2, SIZE_ARRAY_2);
    printf("After sort, ");
    show_array(array2, SIZE_ARRAY_2);

    printf("Before sort, ");
    show_array(array3, SIZE_ARRAY_3);
    bubble_sort(array3, SIZE_ARRAY_3);
    printf("After sort, ");
    show_array(array3, SIZE_ARRAY_3);
}

void show_array(int a[], int n)
{
    if(n>0)
        printf("This array has %d items: ", n);
    else
        printf("Error: array size should bigger than zero.\n");

    for(int i=0; i<n; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
}

运行结果:

Before sort, This array has 5 items: 1 4 2 -9 0
After sort, This array has 5 items: -9 0 1 2 4
Before sort, This array has 6 items: 10 5 2 1 9 2
After sort, This array has 6 items: 1 2 2 5 9 10
Before sort, This array has 20 items: 13 -4 11 11 16 -12 -6 10 -8 2 0 5 -5 0 18 16 5 8 -14 4
After sort, This array has 20 items: -14 -12 -8 -6 -5 -4 0 0 2 4 5 5 8 10 11 11 13 16 16 18

分析

时间复杂度

从代码可见,用了两层 for 循环,且每个循环都是 n 的量级,所以冒泡排序的时间复杂度为 O(n^2)。

空间复杂度

因为冒泡排序直接在原址进行,不需要另外的空间,所以空间复杂度是 O(1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值