插入排序:每次将一个元素插入到前面已排好序的子序列中,直到全部插入完成。
插入排序包括:直接插入排序、折半插入排序、希尔排序
一.直接插入排序
(一)不带哨兵
以下按从小到大排序演示
1.原序列:0号位的49做为已完成排序的子序列,后面将1-7号位的元素依次插入到前面
注:如题目无特殊要求,对第一个元素49的处理视为第一趟排序完成,第二趟排序处理38
2.处理1号元素,比较1号位的38和0号位的49大小关系,38<49,使49后移(到1号位),38插入到0号位
代码角度:
先暂存1号位的38:temp = a[1];
判断与前一个位置的大小关系if (a[i] < a[i - 1])
前一个位置的元素后移a[i - 1+1] = a[i - 1];
38插入0号位:a[i-1] = temp;
处理完成
3.处理2号位的记录65
49<65,保持不变
完成
4.以此类推,当处理5号位的13时
13<97,97后移
13<76,76后移
13<65,65后移
13<49,49后移
13<38,38后移
13插入0号位
代码角度:
if (a[i] < a[i - 1])
{
temp = a[i];
for (j = i - 1; j >= 0 && temp < a[j]; j--) //从前一个元素起往前依次检查,原序列中大就后移,小就跳出循环
//当j减为0时,若temp仍小于a[j],0号位元素a[j]后移,j变为-1,跳出循环,在a[j+1]插入temp。如果不加j >= 0,下一轮比较的是a[-1]和temp的关系
a[j + 1] = a[j];//后移
a[j + 1] = temp;//j多减了1,j+1插入temp
}
完成
5.以此类推,处理7号位的49时
将已排好序的子序列中大于49的后移,即456号位的记录后移,49插入4号位
对于同一记录49,在原序列中49在前,带下划线的49在后。完成排序后仍然保持该顺序,说明该算法的稳定的
因此,直接插入排序是稳定的
完整代码(C++)
#include<stdio.h>
#include<iostream>
using namespace std;
void InsertSort(int a[], int n) {
int i,j,temp;
for (i = 1; i < n; i++) {//从数组为1的记录开始依次插入
if (a[i] < a[i - 1])
{
temp = a[i];
for (j = i - 1; j >= 0 && temp < a[j]; j--)
a[j + 1] = a[j];
a[j + 1] = temp;
}
}
}
int main()//主函数可不写
{
int a[5] = { 34,23,12,87,45 };
InsertSort(a, 5);
for (int i = 0; i <= 4; i++)
{
cout << a[i] << " ";
}
}
(二)带哨兵
序列从1开始存,0作为哨兵,作用充当上面的temp,用于临时存值(a[0] = a[i]),初始默认1为已完成排序的子序列,从2开始插入
优势:因待插入元素存放在a[0],当处理完1,j减为0时,待插入元素和a[0]必然相等,一定会跳出for循环,不用添加限制条件j >= 0
不带哨兵代码:for (j = i - 1; j >= 0 && temp < a[j]; j–)
完整代码
#include<stdio.h>
#include<iostream>
using namespace std;
void InsertSort(int a[], int n)
{
int i, j;
for (i = 2; i <= n; i++)
{
if (a[i] < a[i - 1])
{
a[0] = a[i];
for (j = i - 1; a[0] < a[j]; j--)
a[j + 1] = a[j];
a[j+1]=a[0];
}
}
}
int main()
{
int a[6] = { 0,34,23,12,87,45 };
InsertSort(a, 5);//5表示有5个数
for (int i = 1; i <= 5; i++)//从1开始
{
cout << a[i] << " ";
}
}
(三)复杂度
1.空间复杂度:O(1)
2.时间复杂度=关键字对比+移动元素
(1)最好:初始有序,对比关键字n-1次,无需移动,时间复杂度:O(n)
(2)最坏
例如哨兵
共移动3次:2移到0,80移到2,0移到1
共对比2次:a[0]和a[1]对比,a[0]和a[0]对比
以此类推
最坏时间复杂度=O((2+3+…+n)+(3+4+…+n+1))=O(n²)
(3)平均时间复杂度:O(n²)
(4)如果使用链表
移动次数减少,关键字对比次数O(n²),时间复杂度仍为O(n²)
(四)总结