选择排序

  1. 从要排序的数据中找出(选择)最小的那个数,放在所有数据的最左边,记为已排序数据,其余数据记为未排序数据;
  2. 之后从未排序数据中找出(选择)最小的数,放入已排序数据的末尾;(通过交换两个数的位置实现
  3. 直至所有数据全部加入已排序数据中,选择排序结束。
#include <stdio.h>
#include <windows.h>
// #include <ctime>
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable : 4996)

int* selectionSort_1(int* arr, int size) {
    //clock_t start_time = clock();
    for (int i = 0; i < size-1; i++) {
        for (int j = i+1; j < size; j++) {
            // 当发现未排序数据中存在比第一个未排序数小的数时,两者交换位置
            // 交换次数较多、效率较低
            if (arr[i] > arr[j]) {
                int tem = arr[j];
                arr[j] = arr[i];
                arr[i] = tem;
            }            
        }
    }
    //clock_t end_time = clock();
    //arr[size] = end_time - start_time;
    return arr;
}

int* selectionSort_2(int* arr, int size) {
    for (int i = 0; i < size-1; i++) {
        int t = i;  // 保存未排序数据中扫描到的最小数的下标
        for (int j = i+1; j < size; j++) {
            if (arr[t] > arr[j])    t = j;
        }
        int tem = arr[t];
        arr[t] = arr[i];
        arr[i] = tem;
    }
    return arr;
}

int main()
{
    int arr[10] = { 1,25,3,4,85,6,2,4,7,65 };

    int* a = selectionSort_1(arr, 10);
    int* b = selectionSort_2(arr, 10);

    printf("selectionSort_1 的运行结果\n");
    for (int i = 0; i < 10; i++)    printf("%d ", a[i]);
    printf("\n\nselectionSort_2 的运行结果\n");
    for (int i = 0; i < 10; i++)    printf("%d ", b[i]);

    Sleep(3000);
    return 0;
}

插入排序

  1. 将要排序的数据分为两组,并假设第一个元素为已排序的数据,其余元素为未排序的数据;
  2. 将未排序的数据中的第一个数据,与已排序的数据比较,在已排序数据中发现的第一个比该数大的数时,将该数 插入 到第一个比该数大的数的位置;(通过将插入位置之后的元素后移实现
  3. 直到所有的数都插入到已排序数据中,插入排序结束。
#include <stdio.h>
#include <windows.h>
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable : 4996)

void insertionSort(int* arr, int size) {
    for (int j = 1; j < size; j++) {
        for (int i = 0; i < j; i++) {
            if (arr[i] > arr[j]) {
                int tem = arr[j];
                for (int k = j; k > i; k--) {
                    arr[k] = arr[k - 1];
                }
                arr[i] = tem;
                break;
            }
        }
    }
}

int main()
{
    int arr[10] = { 1,25,3,4,85,6,2,4,7,65 };

    insertionSort(arr,10);

    for (int i = 0; i < 10; i++)    printf("%d ", arr[i]);

    Sleep(3000);
    return 0;
}

冒泡排序

  1. 冒泡排序 size 个数,依次比较相邻的两个数,当大数在小数前面时,就交换两个数的位置;
  2. 当从左到右全部扫描一边之后,小数会左移一位,而最大的数会移到最后,此时算作完成一次冒泡;
  3. 第二遍从左到右扫描结束,小数会再次左移一位,而第二大的数会移到倒数第二个位置;
  4. 当完成 size-1 次冒泡后,所有的数全部排序完成,冒泡排序结束。
#include <stdio.h>
#include <windows.h>
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable : 4996)

void bubbleSort_1(int* arr, int size) {
    // 冒泡排序中,i 表示冒泡的次数,而不表示元素下标。
    // 假设有 size 个数要排序,那么最多最需经过 size-1 次冒泡
    for (int i = 0; i < size-1; i++) {
        // 每次冒泡都会完成一个数的排序,所以每次比较的次数较上次减一
        for (int j = 0; j < size-1-i; j++) {
            if (arr[j] > arr[j + 1]) {
                int tem = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tem;
            }
        }
    }
}

// 有时不用达到冒泡排序的最多次数就可以完成排序,可以通过设置 元素交换的标志 优化冒泡排序
void bubbleSort_2(int* arr, int size) {
    for (int i = 0; i < size - 1; i++) {
        bool bubble = false;
        for (int j = 0; j < size - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                int tem = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tem;
                bubble = true;
            }
        }
        if (bubble == false) {
            break;
        }
    }
}

int main()
{
    int arr[10] = { 1,25,3,4,85,6,2,4,7,65 };

    //bubbleSort_1(arr, 10);
    bubbleSort_2(arr, 10);
    for (int i = 0; i < 10; i++)  printf("%d ", arr[i]);

    Sleep(3000);
    return 0;
}

The End

  • 在以上代码的示例中,都是从左至右遍历数据的。此时,选择排序 & 插入排序 已排序的数据先出现在左边,而 冒泡排序 已排序的数据先出现在右边。当然,通过改变遍历的方向可以改变已排序数据先出现的位置。
  • 在传统解释中,选择排序,即 选择 未排序数据中最小的数,排列到已排序数据的末尾。
  • 插入排序,即将未排序数据中的第一个数据 插入 到已排序数据的合适位置。这两者都较容易理解。
  • 冒泡排序,一般理解为使较小的数像冒泡一样逐渐上浮至靠前排的位置。而笔者认为,冒泡排序更明显的特征在于,每一次冒泡都会使未排序的数据中最大的那个数据沉淀到最右边(从左至右扫描时)。所以对笔者而言,可能叫“沉淀排序”比冒泡排序更容易理解些。