插入排序
代码
C语言代码:
#include <stdio.h>
void insertion_sort(int arr[], int n) {
int i, j, key;
for (i = 2; i <= n; i++) { // 从第二个元素开始
key = arr[i];
for (j = i - 1; arr[j] > key; j--) {
arr[j + 1] = arr[j];
}
arr[j + 1] = key;
}
}
int main() {
int arr[] = {-1000000, 12, 11, 13, 5, 6}; // 使用一个非常小的值作为哨兵,第一个元素不会被排序
int n = sizeof(arr)/sizeof(arr[0]) - 1; // 计算有效长度(去掉哨兵)
insertion_sort(arr, n);
printf("Sorted array: ");
for (int i = 1; i <= n; i++) { // 从第一个实际元素开始打印
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
代码解释
- 初始化:数组
arr
的第一个元素-1000000
作为哨兵,用于边界检查。排序部分从第二个元素开始。 - 主排序循环:
- 从第二个元素(即下标为2)开始遍历,每次将当前元素存入
key
。 - 内部
for
循环从当前元素的前一个位置开始向前遍历,如果当前元素比key
大,则将其向后移动一位,直到找到合适位置插入key
。
- 从第二个元素(即下标为2)开始遍历,每次将当前元素存入
- 结果输出:排序完成后,输出排序后的数组,忽略第一个哨兵元素。
示例运行
假设输入数组为 {-1000000, 12, 11, 13, 5, 6}
:
- 初始状态:
{-1000000, 12, 11, 13, 5, 6}
- 插入 11:
{-1000000, 11, 12, 13, 5, 6}
- 插入 13:
{-1000000, 11, 12, 13, 5, 6}
- 插入 5:
{-1000000, 5, 11, 12, 13, 6}
- 插入 6:
{-1000000, 5, 6, 11, 12, 13}
最终结果:{5, 6, 11, 12, 13}
时间复杂度分析
插入排序的时间复杂度主要取决于数组的初始顺序。
- 最优时间复杂度:当输入数组已经有序时,插入排序只需要进行 次比较,时间复杂度为 。
- 最坏时间复杂度:当输入数组是逆序时,插入排序需要进行最多的比较和移动操作,时间复杂度为 。
- 平均时间复杂度:插入排序在一般情况下的时间复杂度为 。
空间复杂度分析
插入排序是一种原地排序算法,不需要额外的辅助空间,空间复杂度为 。在本实现中,我们仅使用了几个额外的变量(i
, j
, key
),因此空间复杂度保持为常数级别。
优缺点
优点:
- 简单易实现。
- 对于小规模数据集表现良好。
- 稳定排序算法,不改变相同元素的相对顺序。
- 原地排序,空间复杂度低。
缺点:
- 对于大规模数据集,时间复杂度较高,不适合处理大量数据。
适用场景
插入排序适用于以下场景:
- 数据量较小的排序。
- 数组已经部分有序时,插入排序效率较高。
- 需要一个简单且稳定的排序算法时。
总结
插入排序是一种简单直观的排序算法,尽管其最坏情况下时间复杂度较高,但在特定场景下仍然具有优势,特别是对于小规模或部分有序的数据集。使用哨兵元素可以减少边界检查,提高算法的效率。