【最简单最直观的排序 —— 插入排序算法】
插入排序是一种简单直观的排序算法。其基本思想是把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。
插入排序的核心就是多趟选择插入。当插入第 i(i>=1)
个元素时,前面的 array(0),array(1),…,array(i - 1)
已经排好序,此时用 array(i)的排序码与 array(i - 1),array(i - 2),…
的排序码顺序进行比较,找到插入位置即将 array(i)
插入,原来位置上的元素顺序后移。
以升序排序为例,假若有 N 个数
第一次插入:因为第 0 个位置可以看作已经排好序了,将 array(1)看作是被插入的数据,即让被插入的数据与 (0, i ) 区间的元素数据相比,若遇到数据比被插入的数据要大,遇到的数据后移一位,若遇到数据比被插入的数据要小,就将被插入的数据插入到该数据的后面。这样排好之后,前两个数据就变得有序了。
第二次插入:i == 2,此时前两个数据是有序的,即是将 array(2)看作是被插入的数据,在往前进行观察选择插入……
最后一次插入:i==N - 1,此时前 N - 1 个数据是有序的,将 array(N - 1)看作是被插入的数据,在往前进行观察选择插入。这一趟选择插入之后,这整个数组序列就变得有序了。
以下是用 C 语言实现的插入排序代码示例:
#include<stdio.h>
// 插入排序
void InsertSort(int* a, int n)
{
for (int i = 1; i < n; i++) // 决定所插入数据的位置 和 决定插入遍历的次数
{
int tem = a(i); // 被插入的数据
int end = i - 1; // 决定 与被插入的数据相比较 的区间
while (end >= 0) // 结束条件:全部数据比较完成,该循环目的是:找到比被插入数据要小的值的位置
{
if (a(end) > tem) // 已排好的数组中 end 的位置上的数 比 所要插入的数 大就交换
{
a(end + 1) = a(end); // 大数往后移一位
end--; // end 往前走一步
}
else// 有数据比 被插入的数据要小,跳出循环
{
break;
}
}
a(end + 1) = tem; // 将要插入的数插入到 end 位置的后一位。
}
}
int main()
{
int a() = { 29,10,14,37,12,6,32 };
int sz = sizeof(a) / sizeof(a(0)); // 获取数组的大小
printf("插入排序:\n");
for (int i = 0; i < sz; i++) // 打印排序前的序列
{
printf("%d ", a(i));
}
printf("\n");
InsertSort(a, sz); // 执行 插入排序 函数
for (int i = 0; i < sz; i++) // 打印排序后的序列
{
printf("%d ", a(i));
}
printf("\n");
return 0;
}
此外,插入排序还有多种语言的实现方式,如 Python:
def insertionSort(arr):
for i in range(1, len(arr)):
key = arr(i)
j = i - 1
while j >= 0 and key < arr(j) :
arr(j + 1) = arr(j)
j -= 1
arr(j + 1) = key
arr = (12, 11, 13, 5, 6)
insertionSort(arr)
print ("排序后的数组:")
for i in range(len(arr)):
print ("%d" %arr(i))
插入排序算法适用于少量数据的排序,时间复杂度为 O(n²),是稳定的排序方法。
插入排序算法的时间复杂度分析
插入排序的时间复杂度取决于待排序序列中元素的值。当待排序序列的长度为 n 时,最坏情况下的时间复杂度为 O(n²)
,因为每次插入都需要比较相邻的元素。例如,对于一个逆序排列的序列,每次插入新元素都需要与已排序部分的所有元素进行比较和移动。然而,在实际应用中,插入排序的平均时间复杂度也为 O(n²)
。但在最好情况下,即排序表本身是有序的,此时只需比较 n - 1 次,没有移动的记录,时间复杂度为 O(n)
。插入排序的时间复杂度分析主要基于其算法的基本操作,即每次从无序序列中取出一个元素,然后在已排序序列中找到合适的位置插入。这种操作在不同情况下的执行次数不同,导致了不同的时间复杂度表现。
插入排序算法的适用场景
插入排序通常用于小型数据集的排序。其排序过程类似于我们打牌时将手中的牌按照从小到大的顺序整理。插入排序的基本思想是将未排序的元素依次插入已排序的元素中,直到所有元素都有序。插入排序适用于以下场景:一是数据量较小的情况,例如量级小于千。在小型数据集上,插入排序的效率比较高,因为其时间复杂度虽然为 O(n²)
,但对于小规模数据,这个复杂度并不会造成太大的性能问题。二是若已知输入元素大致上按照顺序排列,此时插入排序效率较高。因为在这种情况下,插入排序的比较和移动操作会大大减少,时间复杂度接近最好情况的 O(n)。例如,对于一个已经部分有序的序列 [2, 4, 3, 5, 1],使用插入排序可以快速将其排序为 [1, 2, 3, 4, 5]。
C 语言插入排序代码示例分析
以下是 C 语言插入排序的代码示例分析:
void _sort(int a[],int n)
{
//进行 N-1 轮插入过程
for(int i=1; i<n; i++)
{
//首先找到元素 a[i]需要插入的位置
int j=0;
while( (a[j]<a[i]) && (j<n))
j++;
//将元素 a[i]插入到正确位置
int temp = a[i];
for(int k=i; k>j; k--)
a[k] = a[k-1];
a[j] = temp;
}
}
在这段代码中,首先进行N - 1
轮插入过程。每一轮中,从无序序列中取出一个元素,即数组中的 a[i]。然后通过一个 while 循环找到这个元素在已排序序列中的正确位置 j。如果 a[j]小于 a[i],则继续寻找下一个位置;如果 a[j]大于等于 a[i],则找到了插入位置。接着,将从插入位置到当前元素位置之间的元素向后移动一位,为新元素腾出位置。最后,将新元素插入到正确位置 j。这个过程体现了插入排序的基本思想,即每次将一个未排序的元素插入到已排序的序列中,保持已排序序列的有序性。
Python 插入排序代码示例分析
以下是 Python 插入排序的代码示例分析:
def insert_sort(arr):
# 从第二个元素开始循环,因为第一个元素默认是有序的
for i in range(1, len(arr)):
# 从后往前比较,如果当前元素比前一个元素小,就交换位置
while i > 0 and arr[i] < arr[i - 1]:
arr[i], arr[i - 1] = arr[i - 1], arr[i]
i -= 1
return arr
在这段 Python 代码中,首先从第二个元素开始遍历数组。对于每个元素,从当前位置开始向前面的已排序部分进行比较。如果当前元素小于前一个元素,就交换它们的位置,并继续向前比较,直到找到合适的位置插入当前元素。这个过程与插入排序的基本思想一致,通过不断地将未排序元素插入到已排序部分的正确位置,最终实现整个数组的有序排列。
总结
插入排序算法是一种简单直观的排序算法,适用于小型数据集或部分有序的情况。它具有稳定性,时间复杂度在最坏情况下为 O(n²),但在最好情况下为 O(n)。C 语言和 Python 的代码示例展示了插入排序的具体实现方式,通过比较和移动元素,将未排序的元素逐步插入到已排序的序列中。在实际应用中,根据数据规模和特点,可以选择插入排序或其他更高效的排序算法。