插入排序分为直接插入排序、折半插入排序、希尔排序(shell sort),后两种是在直接插入排序的改进上而来。本文主要介绍直接插入排序算法。
直接插入排序
基本思想
假设待排序的元素存放在数组
A
[
1..
n
]
A[1..n]
A[1..n]中,在排序过程的某一时刻,A被划分为两个子区间
A
[
1..
m
i
d
]
A[1..mid]
A[1..mid]和
A
[
m
i
d
+
1..
n
]
A[mid+1..n]
A[mid+1..n],其中前一个子区间为排好序的有序区,而后一个子区间为未排序的子区间,暂称作无序区。该排序算法顾名思义,取出无序区的第一个元素
A
[
m
i
d
+
1
]
A[mid+1]
A[mid+1]插入到有序区
A
[
1..
m
i
d
]
A[1..mid]
A[1..mid]中适当的位置,
A
[
1..
m
i
d
+
1
]
A[1..mid+1]
A[1..mid+1]变成新的有序区(假设按照升序排序)。动画演示如下:
对于第i趟排序,要将无序区的第一个元素
A
[
m
i
d
+
1
]
A[mid+1]
A[mid+1](设
A
[
m
i
d
+
1
]
A[mid+1]
A[mid+1]的值为
a
a
a)插入到有序区的适当位置,此时便将
a
a
a不断的与有序区的元素进行比较(即为动画中红色条形与绿色条形的部分),当找到第一个比
a
a
a小的元素时(假设是
A
[
m
]
(
1
≤
m
<
m
i
d
+
1
)
A[m](1≤m<mid+1)
A[m](1≤m<mid+1)),在该元素的后面将
a
a
a插入,当
a
a
a是有序区中最小的元素时,将a放在有序区的第一个位置,此时数组中下标
m
+
1
m+1
m+1到
m
i
d
mid
mid的所有元素均要往后移动一格,就像是腾出一个位置来让给
a
a
a,然后把
a
a
a放到数组中
m
m
m的位置。
代码实现
案例:待排序数组:{ 95, 23, 40, 6, 98, 13, 66, 33 }
#include <iostream>
#include <vector>
using namespace std;
class Sort {
public:
void InsertionSort(vector<int> &num)
{
for (int i = 1; i < num.size(); i++)
{
int j = i - 1;
int temp = num[i];
while (j >= 0 && num[j] > temp)
{
num[j + 1] = num[j];
j--;
}
num[j + 1] = temp;
}
}
};
int main()
{
vector<int>num;
num.push_back(95);
num.push_back(23);
num.push_back(40);
num.push_back(6);
num.push_back(98);
num.push_back(13);
num.push_back(66);
num.push_back(33);
printf("排序前:");
for (vector<int>::iterator it = num.begin(); it != num.end(); it++)
{
cout << *it << ' ';
}
cout << endl;
printf("排序后:");
Sort S1;
S1.InsertionSort(num);
for (vector<int>::iterator it = num.begin(); it != num.end(); it++)
{
cout << *it << ' ';
}
system("pause");
return 0;
}
结果输出
算法分析
- 空间复杂度:因为直接插入排序并没有开第二个数组,它仅仅只是就着他自己的原来的数组进行排序,利用的存储空间是常数个空间,因而其空间复杂度为 O ( 1 ) O(1) O(1),即原地工作。
- 时间复杂度:在排序过程中,向有序区逐个的插入元素进行了
n
−
1
n−1
n−1趟,每趟都分为两步:
(1) 和前一元素进行比较
(2) 将前一元素进行往后挪
其中比较的次数与待排序数组的初始状态有关,在最优情况下,表中元素已有序,此时每遍历一次,都不用移动元素,且只需比较一次,时间复杂度为 O ( n ) O(n) O(n)。在最坏情况下,数组中元素与要排序顺序相反(如上动图中案例所示),总的比较次数达到最大均为 O ( n 2 ) O(n^2) O(n2)。平均情况下总的比较次数和移动次数约为 n 2 4 \frac{n^2} {4} 4n2 ,所以时间复杂度为 O ( n 2 ) O(n^2) O(n2)。 - 稳定性:每次插入元素时,总是从后向前比较再移动,所以相同元素的相对位置不会发生变化,直接插入排序是一个稳定的排序算法。
- 适用性:直接插入排序适用于顺序存储和链式存储的线性表。
参考链接:https://blog.csdn.net/five_east_west/article/details/118501158