数据结构——折半插入排序

折半插入排序

直接插入排序在确定插入位置时,需要逐个比较已排序区间的元素,当已排序区间较长时,比较次数较多。折半插入排序则利用"已排序区间是有序的"这一特性,通过折半查找快速确定插入位置,从而减少比较次数,是对直接插入排序的高效优化。

1. 折半插入排序的执行流程

我们以数组arr = {49, 38, 65, 97, 76, 13, 27, 49}为例,详细演示折半插入排序的每一步:

  • 初始状态 :已排序区间为[49],未排序区间为{38, 65, 97, 76, 13, 27, 49}
  • 第1次插入(处理38)
    目标是将38插入到已排序区间[49]的合适位置。
    ① 折半查找插入位置:定义low=0high=0(已排序区间长度为1),计算mid = (low+high)/2 = 0。比较arr[mid]=493838 < 49,所以插入位置在mid左侧,更新high=mid-1=-1,此时low > high,确定插入位置为low=0
    ② 移动元素并插入:将49后移一位,把38插入到arr[0]位置。数组变为{38, 49, 65, 97, 76, 13, 27, 49},已排序区间扩展为[38, 49]
  • 第2次插入(处理65)
    已排序区间为[38, 49],处理未排序区间的65
    ① 折半查找:low=0high=1mid=(0+1)/2=0。比较arr[mid]=386565 > 38,更新low=mid+1=1;再次计算mid=(1+1)/2=1,比较arr[mid]=496565 > 49,更新low=mid+1=2,此时low > high,确定插入位置为low=2
    ② 移动元素并插入:65直接插入到49后面,数组不变,已排序区间扩展为[38, 49, 65]
  • 第3次插入(处理97)
    已排序区间为[38, 49, 65],处理97
    折半查找后,发现97大于已排序区间的最大元素65,直接插入到末尾,数组不变。
  • 第4次插入(处理76)
    已排序区间为[38, 49, 65, 97],处理76
    ① 折半查找:low=0high=3mid=1arr[1]=49 < 76),更新low=2mid=2arr[2]=65 < 76),更新low=3mid=3arr[3]=97 > 76),更新high=2,此时low > high,确定插入位置为low=3
    ② 移动元素并插入:将97后移,把76插入到6597之间,数组变为{38, 49, 65, 76, 97, 13, 27, 49}
  • 后续插入(处理13、27、49)
    按照同样的折半查找逻辑,13会被插入到最前面,27插入到13之后,最后一个49会插入到已排序区间中第一个49的后面(保持相同元素的相对顺序,算法稳定)。最终数组变为{13, 27, 38, 49, 49, 65, 76, 97}
2. 折半插入排序的代码实现

以下是折半插入排序的C语言实现,核心是用折半查找确定插入位置,再移动元素完成插入:

c 复制代码
void BinaryInsertSort(int arr[], int n) {
    int i, j, low, high, mid, temp;
    for (i = 1; i < n; i++) {
        temp = arr[i];            // 取出未排序区间的第一个元素
        low = 0; high = i - 1;   // 已排序区间的范围[low, high]
        while (low <= high) {     // 折半查找插入位置
            mid = (low + high) / 2;
            if (arr[mid] > temp) high = mid - 1;
            else low = mid + 1;
        }
        for (j = i; j > low; j--) {  // 移动元素,腾出插入位置
            arr[j] = arr[j - 1];
        }
        arr[low] = temp;         // 插入元素
    }
}

代码说明:

  • 外层循环i遍历未排序区间的起始位置;
  • 折半查找阶段:通过lowhigh缩小范围,最终low即为插入位置;
  • 元素移动阶段:从i位置开始,将元素后移,直到low位置,再将temp插入。
3. 折半插入排序的性能与特性
  • 时间复杂度
    折半查找的时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn),但元素移动的次数仍与直接插入排序相同,因此整体时间复杂度仍为 O ( n 2 ) O(n^2) O(n2)。不过,由于减少了比较次数,实际运行效率比直接插入排序更高。
  • 空间复杂度 :仅需一个临时变量temp,空间复杂度为 O ( 1 ) O(1) O(1)。
  • 稳定性 :相同元素插入时,相对顺序不会改变,因此折半插入排序是稳定的
4. 适用场景

折半插入排序适合已排序区间较长 的场景,此时折半查找的优势能充分体现,减少大量比较操作。例如,对基本有序的数组进行排序,或数据量中等(如 n n n在几百到几千之间)的情况,它的效率比直接插入排序更优。

综上,折半插入排序通过折半查找优化了"确定插入位置"的过程,在比较次数上有明显优势,且保持了直接插入排序的稳定性和空间效率,是插入排序家族中更高效的实现方式。理解其"折半查找+元素移动"的逻辑,能为后续学习更复杂的排序算法提供思路。

相关推荐
kyle~1 小时前
排序---常用排序算法汇总
数据结构·算法·排序算法
AndrewHZ1 小时前
【遥感图像入门】DEM数据处理核心算法与Python实操指南
图像处理·python·算法·dem·高程数据·遥感图像·差值算法
CoderYanger1 小时前
动态规划算法-子序列问题(数组中不连续的一段):28.摆动序列
java·算法·leetcode·动态规划·1024程序员节
有时间要学习2 小时前
面试150——第二周
数据结构·算法·leetcode
freedom_1024_2 小时前
红黑树底层原理拆解
开发语言·数据结构·b树
liu****2 小时前
3.链表讲解
c语言·开发语言·数据结构·算法·链表
minji...2 小时前
Linux 基础IO(一) (C语言文件接口、系统调用文件调用接口open,write,close、文件fd)
linux·运维·服务器·网络·数据结构·c++
第二只羽毛3 小时前
C++ 高性能编程要点
大数据·开发语言·c++·算法
CQ_YM3 小时前
数据结构之栈
数据结构·算法·
爱学习的梵高先生3 小时前
C++:基础知识
开发语言·c++·算法