冒泡排序(Bubble Sort)

目录

  • 1.冒泡排序
    • [1.1 基本原理](#1.1 基本原理)
    • [1.2 例子](#1.2 例子)
    • [1.3 示例代码](#1.3 示例代码)
  • 2.魔炮排序
    • [2.1 基本原理](#2.1 基本原理)
    • [2.1 例子](#2.1 例子)
    • [2.2 示例代码](#2.2 示例代码)

1.冒泡排序

1.1 基本原理

冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地遍历待排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

冒泡排序的基本思想是:

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
    这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端,故名。

冒泡排序的时间复杂度在最坏和平均情况下都是 O(n^2),其中 n 是列表的长度。

解释如下:

  1. 最坏情况下,即输入数组完全逆序,需要进行 n(n-1)/2 次比较和交换,所以最坏情况下的时间复杂度是 O(n^2)。
  2. 平均情况下,需要进行近似 n(n-1)/4 次比较和交换,所以平均情况下的时间复杂度也是 O(n^2)。
    在最好情况下,即输入数组已经完全有序,冒泡排序只需要进行 n-1 次比较,不需要进行交换,所以最好情况下的时间复杂度是 O(n)。

1.2 例子

冒泡排序的基本思想是:每次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就将他们交换过来。

举例说明,假设我们有一个待排序的数列:[5, 3, 8, 6, 1]

  1. 第一轮排序,从第一个元素开始,比较相邻的两个元素,如果第一个元素大于第二个元素,就交换他们。这一轮结束后,最大的元素会被放到数列的最后。数列变为:[3, 5, 6, 1, 8]
  2. 第二轮排序,同样从第一个元素开始,重复上述过程,但是最后一个元素(这里是8)可以忽略,因为它已经是最大的元素。数列变为:[3, 5, 1, 6, 8]
  3. 第三轮排序,重复上述过程,忽略最后两个元素(这里是6和8)。数列变为:[3, 1, 5, 6, 8]
  4. 第四轮排序,重复上述过程,忽略最后三个元素(这里是5、6和8)。数列变为:[1, 3, 5, 6, 8]
    此时,所有元素已经排序完成。

1.3 示例代码

复制代码
#include <stdio.h>

void bubbleSort(int arr[], int n) {
   int i, j, temp;
   for(i = 0; i < n-1; i++) {     
       for (j = 0; j < n-i-1; j++) { 
           if (arr[j] > arr[j+1]) { 
               // 交换 arr[j] 和 arr[j+1]
               temp = arr[j];
               arr[j] = arr[j+1];
               arr[j+1] = temp;
           }
       }
   }
}

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

int main() {
   int arr[] = {64, 34, 25, 12, 22, 11, 90};
   int n = sizeof(arr)/sizeof(arr[0]);
   bubbleSort(arr, n);
   printf("Sorted array: \n");
   printArray(arr, n);
   return 0;
}

这段代码首先定义了一个 bubbleSort 函数,用于执行冒泡排序。然后定义了一个 printArray 函数,用于打印数组。在 main 函数中,我们创建了一个数组,并调用 bubbleSort 函数对其进行排序,然后打印排序后的数组。

2.魔炮排序

2.1 基本原理

魔炮排序(Cocktail Sort)也被称为双向冒泡排序,是冒泡排序的一种变形。它在对待排序的数列进行遍历时,是双向进行的,也就是说,每一轮遍历都分为两个方向,一个是从前往后,一个是从后往前。

魔炮排序的基本思想是:

  1. 首先,从左到右比较相邻的元素,如果左边的元素大于右边的元素,就交换他们。这一步完成后,最大的元素会被放到数列的最右边。
  2. 然后,从右到左比较相邻的元素,如果右边的元素小于左边的元素,就交换他们。这一步完成后,最小的元素会被放到数列的最左边。
  3. 重复以上步骤,直到没有元素需要交换。

魔炮排序(Cocktail Sort)的时间复杂度和冒泡排序一样,都是 O(n^2)。

在最好的情况下,如果输入的数据已经是排序好的,那么魔炮排序只需要进行一次遍历,所以最好的情况下时间复杂度是 O(n)。

但是在最坏的情况下,例如输入的数据是逆序的,那么魔炮排序需要进行 n(n-1)/2 次比较,所以最坏的情况下时间复杂度是 O(n^2)。

平均情况下,魔炮排序的时间复杂度也是 O(n^2)。

2.1 例子

举例说明,假设我们有一个待排序的数列:[5, 1, 4, 2, 8, 0, 2]

  1. 第一轮从左到右的排序后,数列变为:[1, 4, 2, 5, 0, 2, 8]
  2. 第一轮从右到左的排序后,数列变为:[0, 1, 2, 4, 2, 5, 8]
  3. 第二轮从左到右的排序后,数列变为:[0, 1, 2, 2, 4, 5, 8]
  4. 第二轮从右到左的排序后,数列变为:[0, 1, 2, 2, 4, 5, 8]
    此时,所有元素已经排序完成。

2.2 示例代码

复制代码
#include <stdio.h>

void cocktailSort(int a[], int n) {
    int swapped = 1;
    int start = 0;
    int end = n - 1;

    while (swapped) {
        swapped = 0;
        for (int i = start; i < end; ++i) {
            if (a[i] > a[i + 1]) {
                int temp = a[i];
                a[i] = a[i + 1];
                a[i + 1] = temp;
                swapped = 1;
            }
        }

        if (!swapped)
            break;

        swapped = 0;
        --end;

        for (int i = end - 1; i >= start; --i) {
            if (a[i] > a[i + 1]) {
                int temp = a[i];
                a[i] = a[i + 1];
                a[i + 1] = temp;
                swapped = 1;
            }
        }
        ++start;
    }
}

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

int main() {
    int a[] = {5, 1, 4, 2, 8, 0, 2};
    int n = sizeof(a) / sizeof(a[0]);
    cocktailSort(a, n);
    printf("Sorted array: \n");
    printArray(a, n);
    return 0;
}

这段代码首先定义了一个 cocktailSort 函数,用于执行魔炮排序。然后定义了一个 printArray 函数,用于打印数组。在 main 函数中,我们创建了一个数组,并调用 cocktailSort 函数对其进行排序,然后打印排序后的数组。

相关推荐
Han.miracle10 小时前
数据结构——二叉树的从前序与中序遍历序列构造二叉树
java·数据结构·学习·算法·leetcode
mit6.82412 小时前
前后缀分解
算法
独自破碎E12 小时前
判断链表是否为回文
数据结构·链表
你好,我叫C小白12 小时前
C语言 循环结构(1)
c语言·开发语言·算法·while·do...while
寂静山林15 小时前
UVa 10228 A Star not a Tree?
算法
Neverfadeaway15 小时前
【C语言】深入理解函数指针数组应用(4)
c语言·开发语言·算法·回调函数·转移表·c语言实现计算器
Madison-No716 小时前
【C++】探秘vector的底层实现
java·c++·算法
Swift社区16 小时前
LeetCode 401 - 二进制手表
算法·leetcode·ssh
派大星爱吃猫16 小时前
顺序表算法题(LeetCode)
算法·leetcode·职场和发展
liu****16 小时前
8.list的模拟实现
linux·数据结构·c++·算法·list