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

折半插入排序

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

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在几百到几千之间)的情况,它的效率比直接插入排序更优。

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

相关推荐
2301_800256113 小时前
地理空间数据库作业笔记——查询最偏僻的城市
数据库·笔记·sql·postgresql·1024程序员节
yi碗汤园3 小时前
【一文了解】八大排序-插入排序、希尔排序
开发语言·算法·unity·c#·1024程序员节
Icoolkj3 小时前
Edge-TTS+Cloudflare Worker:免费 TTS 服务搭建指南,支持 API 调用与低代码集成
1024程序员节
小莞尔3 小时前
【51单片机】【protues仿真】基于51单片机智能温控风扇系统
c语言·单片机·嵌入式硬件·物联网·51单片机·1024程序员节
呆呆小金人3 小时前
Linux:开源时代的隐形基石
linux·1024程序员节
没有bug.的程序员3 小时前
Spring 常见问题与调试技巧
java·后端·spring·动态代理·1024程序员节
Han.miracle3 小时前
数据结构——排序的超级详解(Java版)
java·数据结构·学习·算法·leetcode·排序算法·1024程序员节
hazy1k3 小时前
51单片机基础-DS18B20温度传感器
c语言·stm32·单片机·嵌入式硬件·51单片机·1024程序员节