冒泡排序

冒泡排序重复访问要排序的序列,每次比较两个元素,如果顺序错误就交换这两个元素。直到全部遍历和比较所有元素之后结束排序。

冒泡排序对n个项目需要O(n²)的比较次数,对于大量元素的排序效率很低。

冒泡排序与插入排序拥有相等的执行时间,但是两种算法交换次数有很大的不同。在最坏情况下,冒泡需要O(n²)次交换,而插入排序只要最多O(n)次交换。冒泡排序会对已经排好序的数列执行O(n²)次比较,而插入排序再这里只需要O(N²)次运算。冒泡排序如果在内部的第一次循环运行时,使用一个旗标来表示有无需要交换的可能,也可以把最优情况下的复杂度降低到O(n)。在这种情况下,已经排序好的序列就无交换的需要。

冒泡排序算法的步骤

  • 比较相邻的元素。如果第一个比第二个大,就交换他们两个
  • 对每一个相邻的元素作同样的操作,从开始第一对到结尾最后一对。这步做完后,最后的元素会是最大的元素。
  • 针对所有的元素重复以上的步骤,出了最后一个。
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对元素需要比较

具体实现:

  • 原数组:6 5 4 3 2 1
  • 第一次循环:5 4 3 2 1 6
  • 第二次循环:4 3 2 1 5 6
  • 第三次循环:3 2 1 4 5 6
  • 第四次循环:2 1 3 4 5 6
  • 第五次循环:1 2 3 4 5 6
int bubbleSort(int a[], int count)
{
    int i, j, tmp;
    for (i = 0;i < count - 1;++i)
    {
        for (j = 0;j < count - 1 - i;++j)
        { 
            if (a[j] > a[j+1])
            {
                tmp = a[j];
                a[j] = a[j + 1];
                a[j+1] = tmp;
            }
        }
    }
}

优化1(优化外层循环)

原数组本来就是有序的:1,2,3,4如果我们还是按照上述方法执行,那么还是要执行n-1次,于是我们就需要在没跑完一趟就判断一次原数组现在是否有序,如果有序,直接return掉;

  • 原数组:1 2 3 4
  • 第一次循环:1 2 3 4

因为原本的序列就是有序的,所以并不会进入内层循环

int bubbleSort1(int a[], int count) 
{
    int i = 0;
    int j = 0;

    for (i = 0; i < count - 1; ++i)
    {
        int flag = 1; // 假定每次进入都是有序的flag设为1
        for (j = 0; j < count - i - 1; ++j)
        {
            int tmp = 0;
            if (a[j] > a[j + 1])
            {
                tmp = a[j];
                a[j] = a[j + 1];
                a[j+1] = tmp;
                flag = 0; // 如果发生交换,则flag置为0
            }
        }
        if (flag == 1) // 如果这趟走完,没有发生交换,则原数组有序
            break;
    }

}

优化2(减少内部循环比较的次数)

void bubbleSort2(int a[], int count) 
{
    int i = 0;
    int j = 0;
    int k = count - 1; // 控制内部比较循环
    int n = 0;

    for (i = 0; i < count - 1; ++i)
    {
        int flag = 1;
        n = 0;
        // 假定每次进入都是有序的flag为1
        for (j = 0; j < k; ++j)
        {
            int tmp = 0;
            if (a[j] > a[j+1])
            {
                tmp = a[j];
                a[j] = a[j+1];
                a[j+1] = tmp;
                flag = 0; // 如果发生交换,则flag置位0
                n = j; // 保存最后一次交换的下标
            }
        }

        if (flag == 1) // 如果这趟走完,没有发生交换,则原数组有序;
            break;
        k = n; // 最后一次交换的位置给k,减少比较的次数;
    }
}

0 Comments latest

No comments.