算法-冒泡排序

310 阅读3分钟

冒泡排序

日常生活中,烧开水时,热水壶底部会产生大量小气泡,气泡会自底向上浮动到水面

冒泡排序(Bubble Sort):排序算法中的每一个元素根据自身大小,都可以像小气泡一样向数组的一侧移动.

排序基本思想

  • 1:依次比较相邻的两个元素,当一个元素大于右侧相邻的元素时,交换它们的位置;否则,位置保持不变
  • 2:循环逻辑:从数组第i = 0个元素开始和剩余[n - i - 1]个元素依次进行比较和交换位置

算法

原始版本

数据:{2, 1, 8, 9, 5, 4, 3, 0, 7, 6, 10}

// 测试数据
// 从小到大排序
void bubbleSort(int *array, int length) {
    for(int i = 0; i < length - 1; i++) {
        for (int j = i + 1; j < length; j++) {
            if(array[i] > array[j]) {
                // 交换相邻的两个元素的位置
                array[i] ^= array[j];
                array[j] ^= array[i];
                array[i] ^= array[j];
            }
        }
    }
}

优化一

数组本来就有序的情况

数据:{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

原理:利用isSorted作为标记,如果本轮排序中有元素交换,那么说明数组无序;否则,说明数组是有序的,直接退出循环

void bubbleSort(int *array, int length) {
    for(int i = 0; i < length - 1; i++) {
        // 标记是否已经排序,每一轮排序前初始为1
        int isSorted = 1;
        for(int j = 0; j < length - i - 1; j++) {
            if (array[j] > array[j+1]) {
                // 交换相邻的两个元素的位置
                array[j] ^= array[j+1];
                array[j+1] ^= array[j];
                array[j] ^= array[j+1];

                // 说明未排序
                isSorted = 0;
            }
        }
        if (isSorted) {
            break;
        }
    }
}

优化二

数组前半部分无序,后半部分为有序的情况

数据:{5, 1, 2, 4, 0, 3, 6, 7, 8, 9, 10}

原理:

  • 1:确定数组有序区域的边界
  • 2:每一轮排序后,记下最后一次元素交换的位置,该位置即为无序数据区域的边界,后面的即为有序区域了
void bubbleSort(int *array, int length) {
    // 记录最后一次交换的位置
    int lastExchangeIndex = 0;

    // 无序数据的边界,每次比较到这里就停止
    int sorteBorder = length - 1;

    for(int i = 0; i < length - 1; i++) {
        // 有序的标记,每一轮排序前初始为1
        int isSorted = 1;
        for(int j = 0; j < sorteBorder; j++) {
            if (array[j] > array[j+1]) {
                // 交换相邻的两个元素的位置
                array[j] ^= array[j+1];
                array[j+1] ^= array[j];
                array[j] ^= array[j+1];

                // 有元素交换,说明未排序
                isSorted = 0;

                // 记录最后一次交换元素的位置
                lastExchangeIndex = j;
            }
        }
        // 更新未排序边界
        sorteBorder = lastExchangeIndex;
        if (isSorted) {
            break;
        }
    }
}

优化三

鸡尾酒排序:前面排序都是从左向右比较和交换元素,本算法是双向比较和交换,优化点是减少遍历比较的次数

原理:

  • 1:首先从左向右依次比较和交换元素
  • 2:从右向左一次比较和交换
  • 3:再次从左向右依次比较和交换元素
void bubbleSort(int *array, int length) {
    for (int i = 0; i < length/2; i++) {
        // 有序的标记,每一轮排序前初始为1
        int isSorted = 1;

        // 奇数轮,从左向右比较和交换
        for (int j = i; j < length - i - 1; j++) {
            if (array[j] > array[j+1]) {
                // 交换相邻的两个元素的位置
                array[j] ^= array[j+1];
                array[j+1] ^= array[j];
                array[j] ^= array[j+1];

                // 有元素交换,说明未排序
                isSorted = 0;
            }
        }
        if (isSorted) {
            break;
        }
        // 偶数轮,从右向左比较和交换
        isSorted = 1;
        for (int j = length - i - 1; j > i; j--) {
            if (array[j] < array[j-1]) {
                // 交换相邻的两个元素的位置
                array[j] ^= array[j-1];
                array[j-1] ^= array[j];
                array[j] ^= array[j-1];

                // 有元素交换,说明未排序
                isSorted = 0;
            }
        }

        if (isSorted) {
            break;
        }
    }
}