简单插入排序
简单插入排序插入排序,是指将无序序列中的各元素依次插入到已经有序的线性表中。
原理
假设现在有一个有序列表
{a1,a2,...ak}
,要向其中插入一个新的元素
an
,并且保证插入之后的列表也是有序的,那我们要做的就是从后向前找到第一个
ai<=an
,并把
an
放在
ai
后面。
同样的,现在我们要对
{a1,a2,...an}
排序,我们可以先把
a1
插入到有序列表空集中形成新的列表,然后把
a2
插入到新的列表中,依次类推,直到N个元素都插入完毕。每次插入要保证形成的新列表也是有序的。
分析
初始数组 {43512}
- 将4插入到空集中,完成后 4 3 5 1 2
- 将3插入到新列表,完成后 3 4 5 1 2
- 将5插入到新列表,完成后 3 4 5 1 2
- 将1插入到新列表,完成后 1 3 4 5 2
- 将2插入到新列表,完成后 1 2 3 4 5
代码
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void insertionSort(int* arr, int len)
{
for(int i = 1; i < len; i++) {
//查询第一个小于等于要插入元素的元素
int j = i - 1;
while(arr[j] > arr[i]) {
j--;
}
if(j != i - 1) {
int temp = arr[i];
//把从j+1到i位的元素都后移一位
for(int k = i - 1; k > j; k--) {
arr[k + 1] = arr[k];
}
//把要插入的元素放在j+1位
arr[j + 1] = temp;
}
}
}
优化
可以将每个元素与前面有序列表比较的过程改成类似与冒泡排序比较的过程。 ai 从 ai−1 向前比较,直到找到第一个小于等于它的元素。也就是说比较过程中,他经过的都是大于它的元素。我们可以让他每遇到一个大于它的元素,就和这个元素交换位置,这样他就可以一步一步的交换到正确的位置上。
void insertionSort(int* arr, int len)
{
for(int i = 1; i < len; i++) {
for(int j = i; j > 0 && arr[j - 1] > arr[j]; j--) {
swap(arr + j - 1, arr + j);
}
}
}
时间复杂度
在最坏情况下,我们假设每次新元素都是最小的,那么插入第一个元素时需要0次比较,插入第二个元素时需要1次比较,插入第三个元素时需要2次比较……插入第n个元素时需要n-1次比较。
∑i=1n(i−1)=n(n−1)2
所以最坏情况的时间复杂度是 O(n2) 。
在最好的情况下,数组本来就是有序的,那么每插入一个元素,只需要和他前面相邻的元素进行比较就可以了,这种情况下时间复杂度是 O(n) 。