【算法】插入排序 与 希尔排序 概念+图解+代码【Python C C++】

1.插入排序

1.1概念

插入排序(InsertionSort),一般也被称为直接插入排序。

对于少量元素的排序,它是一个有效的算法。插入排序是一种最简单的排序方法,它的基本思想是将一个元素插入到已经排好序的有序表中,从而构造出一个新的、记录数增 1 的有序表。

并假设最开始该有序列表只有第一个元素,将后面的每个元素按顺序依次插入到前面有序列表的合适位置中去即可。

在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。

时间复杂度:O(n^2)

空间复杂度: O(1)

1.2图解(以C语言代码为例)

1.3代码

1.3.1 C

#include <stdio.h>

void insertionSort(int arr[], int n);  // 声明插入排序函数
void printArray(int arr[], int size);  // 声明打印数组函数

int main() {
    int arr[] = {12, 11, 13, 5, 6};  // 定义待排序数组
    int n = sizeof(arr)/sizeof(arr[0]);  // 计算数组长度

    insertionSort(arr, n);  // 调用插入排序函数

    printf("Sorted array: \n");  // 打印排序后的数组
    printArray(arr, n);

    return 0;  // 程序结束
}

void insertionSort(int arr[], int n) {
    int i, key, j;  // 定义局部变量
    for (i = 1; i < n; i++) {  // 从第二个元素开始遍历
        key = arr[i];  // 将当前元素保存为key
        j = i - 1;  // 设置j为前一个元素的索引

        // 移动比key大的元素
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];  // 将元素向右移动
            j = j - 1;  // 移动到下一个元素
        }
        arr[j + 1] = key;  // 将key插入到正确的位置
    }
}

void printArray(int arr[], int size) {
    int i;  // 定义索引变量
    for (i = 0; i < size; i++)  // 遍历数组
        printf("%d ", arr[i]);  // 打印每个元素
    printf("\n");  // 换行
}

1.3.2 Python

def insertionSort(x):
    for i in range(1, len(x)):
        temp = x[i]
        j = i - 1
        while j >= 0 and x[j] > temp:
            x[j+1] = x[j]
            j -= 1
        x[j + 1] = temp


x1 = [2, 5, 2, 1, 9, 4, 7]
print(x1)
insertionSort(x1)
print(x1)

# 输出
[2, 5, 2, 1, 9, 4, 7]
[1, 2, 2, 4, 5, 7, 9]

1.3.3 C++

#include <iostream>

// 插入排序函数
void insertionSort(int arr[], int n) {
    for (int i = 1; i < n; i++) {  // 从第二个元素开始,到数组末尾
        int key = arr[i];  // 保存当前要插入的元素
        int j = i - 1;  // 初始化一个指针,指向当前元素的前一个位置

        // 当 j 大于等于 0 且前一个元素大于当前元素时
        while (j >= 0 && arr[j] > key) {  
            arr[j + 1] = arr[j];  // 将前一个元素向后移动一位
            j = j - 1;  // 将 j 向前移动一位
        }
        arr[j + 1] = key;  // 将当前元素插入到正确的位置
    }
}

// 打印数组函数
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++)
        std::cout << arr[i] << " ";
    std::cout << std::endl;
}

// 测试案例
int main() {
    int arr[] = {12, 11, 13, 5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);

    std::cout << "排序前的数组为: ";
    printArray(arr, n);

    insertionSort(arr, n);

    std::cout << "排序后的数组为: ";
    printArray(arr, n);

    return 0;
}

2.希尔排序

2.1 概念

希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进

希尔排序又称缩小增量排序,因 DL.Shell 于 1959 年提出而得名。

它通过比较相距一定间隔的元素来进行,通过确定分隔间隔(总数除2取整,再递归除2,直到为1)来分出多个数列分别进行从少到多插入排序,各趟比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止

时间复杂度:O(n^(1.3-2))

没有时间复杂度为 O(n(logn)) 的快速排序算法快 ,因此对中等大小规模表现良好,但对规模非常大的数据排序不是最优选择,

比一般 O(n^2 ) 复杂度的算法快得多

空间复杂度: O(1)

可能有人会觉得,希尔排序的最后一步不就相当于插入排序,一个一个加到有序列表中去

但其实希尔排序通过先将数组按照较大的间隔进行分组排序,使得数组在一开始就变得部分有序。随着间隔逐渐缩小,最终达到类似于插入排序的效果。虽然希尔排序的最后一步在较小间隔时类似于插入排序,但由于前面的分组排序操作,使得元素的初始顺序相对较好,减少了插入排序时元素移动的次数。插入排序在最坏情况下,对于一个逆序的数组,每次插入操作都需要移动大量的元素,时间复杂度为 O(n^2)。而希尔排序通过合理选择间隔序列,可以在大多数情况下,有效地减少排序的总比较和移动次数,不过对于希尔排序最坏的情况也是O(n^2),只能说大部分情况下比插入排序优。

2.2 图解(以C语言代码为例)

2.3代码

2.3.1 C 

//gcc -g D:\C\the_C\算法知识相关\希尔排序\2.c -o D:\C\the_C\算法知识相关\希尔排序\b.exe
#include <stdio.h>

// 希尔排序函数
void shellSort(int arr[], int n) {
    int gap, i, j, temp;

    for (gap = n / 2; gap > 0; gap = gap / 2) {
        for (i = gap; i < n; i++) {
            temp = arr[i];
            for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
                arr[j] = arr[j - gap];
            }
            arr[j] = 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[] = {12, 11, 13, 5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("before sorting: ");
    printArray(arr, n);

    shellSort(arr, n);

    printf("after sorting: ");
    printArray(arr, n);

    return 0;
}

2.3.2 python

def ShellSort(x):
    gap = len(x) // 2
    while gap >= 1:
        i = gap
        while i < len(x):
            temp = x[i]
            j = i - gap
            while j >= 0 and x[j] > temp:
                x[j + gap] = x[j]
                j -= gap
            x[j + gap] = temp
            i += 1
        gap //= 2


x1 = [2, 5, 2, 1, 9, 4, 7]
print(x1)
ShellSort(x1)
print(x1)

# 输出
[2, 5, 2, 1, 9, 4, 7]
[1, 2, 2, 4, 5, 7, 9]

2.3.3 C++

#include <iostream>

// 希尔排序函数
void shellSort(int arr[], int n) {
    for (int gap = n / 2; gap > 0; gap /= 2) {
        for (int i = gap; i < n; i++) {
            int temp = arr[i];
            int j;
            for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
                arr[j] = arr[j - gap];
            }
            arr[j] = temp;
        }
    }
}

// 打印数组函数
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
}

// 测试示例
int main() {
    int arr[] = {12, 11, 13, 5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);

    std::cout << "排序前的数组为: ";
    printArray(arr, n);

    shellSort(arr, n);

    std::cout << "排序后的数组为: ";
    printArray(arr, n);

    return 0;
}

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值