数据结构-排序(二)插入排序

本文详细介绍了直接插入排序和折半插入排序的算法思想、代码实现和算法效率分析,还包括直接插入排序可视化动图,易理解!
Let’s go!🏃‍♂️

数据结构-排序(二)插入排序

在这里插入图片描述

一、 直接插入排序

1、算法思想

算法思想: 每次将⼀个待排序的记录按其关键字⼤⼩插⼊到前⾯已排好序的⼦序列中,直到全部记录插⼊完成。

排序过程:

  • 整个排序过程为n-1趟插入,
  • 先将序列中第1个记录看成是一个有序子序列,
  • 然后从第2个记录开始,逐个进行插入,直至整个序列有序。

在这里插入图片描述
以上gif动图制作,图像来自网站:VisuAlgo
链表实现请参考:链表实现直接插入排序

2、代码实现

#include <iostream>
#include <string>
using namespace std;

/**
 * 插入排序
 * @param arr  数组
 * @param n  数据个数
 * @return 
 */
bool InsertSort(int arr[], int n) {
    for (int i = 1; i < n; i++) {
        if (arr[i] < arr[i - 1]) { //若关键字小于前驱
            int t = arr[i]; //暂存关键字
            int j;
            for (j = i - 1; j >= 0 && arr[j] > t ; j--) { //检查前面排序的元素
                arr[j + 1] = arr[j]; //所有大于t的元素完后挪位
            }
            arr[j + 1] = t; //复制到插入位置
        }
    }
}

/**
 * 输出数组
 * @param arr 
 * @param n 
 */
void PrintArray(int arr[], int n) {
    for (int i = 0; i < n; i++) {
        cout << arr[i] << "  ";
    }
    printf("\n");
}
int main() {
    int arr[] = {12, 28, 20, 50, 48, 1, 5, 28};
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << "输出初始数组" << endl;
    PrintArray(arr, n);
    cout << "直接插入排序" << endl;
    InsertSort(arr, n);
    cout << "输出排序后数组" << endl;
    PrintArray(arr, n);
    return 0;
}
输出初始数组
12  28  20  50  48  1  5  28
直接插入排序
输出排序后数组
1  5  12  20  28  28  48  50

3、算法效率分析

1、空间复杂度: O(1)

2、时间复杂度: 主要来⾃对⽐关键字、移动元素若有 n 个元素,则需要 n-1 趟处理

最好情况: 共n-1趟处理,每⼀趟只需要对⽐关键字1次,不⽤移动元素

最好时间复杂度—— O(n)

最坏情况:
第1趟:对比关键字2次,移动元素3次
第2趟:对比关键字3次,移动元素4次

第 i 趟:对比关键字 i+1次,移动元素 i+2 次

最坏时间复杂度——O(n2)

最好时间复杂度(全部有序):O(n)

最坏时间复杂度(全部逆序):O(n2)

平均时间复杂度:O(n2)

3、算法稳定性: 稳定

二、折半插入排序

1、算法思想

算法思想: 先⽤折半查找找到应该插⼊的位置,再移动元素

  • 当 low>high 时折半查找停止,应将 [low, i-1] 内的元素全部右移,并将 A[0] 复制到 low 所指位置
  • 当 A[mid]==A[0] 时,为了保证算法的**“稳定性”**,应继续在 mid 所指位置右边寻找插⼊位置

2、代码实现

/**
 * 折半插入排序
 * @param arr
 * @param n
 * @return
 */
bool SplitInsertSort(int arr[], int n ) {
    for (int i = 2; i <= n ; i++) {
        arr[0] = arr[i]; //暂存关键字
        int low = 1, high = i - 1; //折半查找范围
        while (low <= high) { //折半查找
            int mid = (low + high) / 2;
            if (arr[mid] > arr[0]) { //查找左子表
                high = mid - 1;
            }else { //查找右半子表
                low = mid + 1;
            }
        }
        for (int j = i - 1; j >= high + 1 ; --j) {
            arr[j + 1] = arr[j]; //统一后移操作,空出插入位置
        }
        arr[high + 1] = arr[0]; //插入操作
    }
}

3、算法效率分析

1、空间复杂度: O(1)

2、时间复杂度:

比起“直接插⼊排序”,比较关键字的次数减少了,但是移动元素的次数没变,整体来看时间复杂度依然是O(n2)

3、算法稳定性: 稳定

下一篇👉数据结构-排序(三)希尔排序

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值