冒泡排序

概述

冒泡排序 (bubble_sort) 是计算机领域最经典的一种排序算法,它重复走访要排序的序列,每次比较相邻的两个元素,若次序错误就交换它们,直到整个序列有序。
由于冒泡排序每趟通过交换可以将最大(小)元素换至尾端,类似水中逐渐浮起的水泡,故以此得名。

原理

以排升序为例:

这里写图片描述
如上图所示,其排序步骤如下:

  • 从前至后依次比较相邻元素,若它们的次序错误就交换其位置,直至比较到数组最后一个元素,此时完成一趟冒泡,且最大元素已经“冒”至尾端;
  • 缩小排序范围,重复上述步骤,直至整个序列有序。

时间复杂度:
可以看到,对于 N 个元素的序列需要进行 N-1 趟冒泡,每趟都要遍历序列。在经过优化后,该算法最好的情况是对于有序序列只需遍历一趟,而最坏情况则是逆序需要遍历n趟,它的平均时间复杂度是:O(n^2)
在排序前后,key 值相同元素的相对位置不会发生变化,故该排序算法是稳定的

C语言实现

version 1.0

void BubbleSort(int *a, size_t n)
{
    assert(a);
    for (size_t i = 0; i < n - 1; ++i){
        for (size_t j = 1; j < n - i; ++j){
            if (a[j-1] > a[j]){
                //交换元素
                int tmp = a[j-1];
                a[j-1] = a[j];
                a[j] = tmp;
            }
        }
    }
}

上述代码虽然实现了冒泡排序,但是在处理有序序列时,它的时间复杂度还会是 O(n^2),我们期望的是:当序列有序时,我们就不必再排序。故在此基础上,我们增加一个标记变量,当发现某趟冒泡时,没有发生元素交换,那么说明整个序列已经有序,则无需再排。代码如下:

version 2.0

void BubbleSort(int *a, size_t n)
{
    assert(a);
    bool flag = false;//标记是否有过交换
    for (size_t i = 0; i < n - 1; ++i){
        for (size_t j = 1; j < n - i; ++j){
            if (a[j-1] > a[j]){
                swap(a[j-1], a[j]);
                flag = true;
            }
        }

        if (!flag)//如果没交换过则已经有序,可以直接退出
            break;
    }
}

假如有一序列,它的后半段已经有序,只有前半段是无序的,那么我们每次就无序冒到最后一个元素才停止,所以,我们针对这种情况对 version 1.0 优化,增加一个标记,该标记用于记录每趟排序最后一个发生交换的位置,这样,在下次排序时,只需要排到上次最后一个发生交换的位置即可,这样就完美处理了上述的“后半段有序而前半段无序的情况了”。代码如下:
version 3.0

void BubbleSort(int *a, size_t n)
{
    assert(a);
    int lastSwap = n;
    int pos = lastSwap;
    while (lastSwap > 1){
        pos = 0;
        for (size_t i = 1; i < lastSwap; ++i){
            if (a[i - 1] > a[i]){
                pos = i;
                swap(a[i - 1], a[i]);
            }
        }
        lastSwap = pos;
    }
}

【作者:果冻 http://blog.csdn.net/jelly_9

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值