冒泡排序

来源:互联网 发布:如何设置javascript 编辑:程序博客网 时间:2024/05/22 11:44

概述

冒泡排序 (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】

原创粉丝点击