1、思路:
(1)基本思想:
每趟排序都将一个待排序的数据按照其与前面的已排序序列中的数据的比较后得到的大小关系来找到其在该有序序列中的位置并插入,直到所有的数据都插入到该有序序列中时,排序完成。
(2)步骤:
1.把该组无序的数据的第一个元素看成是有序的;
2.将无序序列的第一个元素与有序序列的数据从后到前依次比较,如何有序序列的数据比待排数据大,则将其向后移动,直到待排数据前的数据都是小于或者等于它的,将该数据插入
3.重复步骤2,直到所有的元素都已经插入到有序序列中。
2、过程
PS:中括号中的数据为已排序的有序序列
已知一组待排序的序列为{52,39,67,97,95,79,8,25,53},则其直接插入的排序过程如下:
第0趟: [52] ,39,67,97,95,79,8,25,53
第1趟: [39,52] ,67,97,95,79,8,25,53
第2趟: [39,52,67] ,97,95,79,8,25,53
第3趟: [39,52,67 ,97] ,95,79,8,25,53
第4趟: [39,52,67 ,95,97] ,79,8,25,53
第5趟: [39,52,67 ,79,95,97] ,8,25,53
第6趟: [8,39,52,67 ,79,95,97] ,25,53
第7趟: [8,25,39,52,67 ,79,95,97] ,53
第8趟: [8,25 ,39,52,53,67 ,79,95,97]
3、代码实现
//直接插入排序算法
//不带监视哨
public static int[] insert(int[] r)
{
int i, j , temp;
for(i = 1;i < r.length ;i++) //从第二个开始与前面的有序序列比较
{
temp = r[i];
for( j = i-1;j >= 0 && temp< r[j] ;j--) //n-1次循环
{
r[j+1] = r[j]; //将比待排数据大的数据后移
}
r[j+1] = temp; //将待排数据插入有序序列中
}
return r;
}
//带监视哨
public static int[] insert(int[] r)
{
int i, j;
for(i = 1;i < r.length ;i++) //从第二个开始与前面的有序序列比较
{
r[0] = r[i];
for( j = i-1;j >= 0 && r[0] < r[j] ;j--) //n-1次循环
{
r[j+1] = r[j]; //将比待排数据大的数据后移
}
r[j+1] = r[0]; //将待排数据插入有序序列中
}
return r;
}
ps:监视哨有两个作用:
(1)第一个作用是用来存储每次待插入的元素,作用和上面那个函数中设置的变量key一样;
(2)设置监视哨确实可以省略判断j>=0这一步,可不要小看了这一步,一次循环少判断一次, n次循环就少判断n次,当要排序的元素数量极其庞大时,提高的效率就十分可观了
4、性能分析
(1)时间复杂度:
序列排序前有序:进行了n-1次循环,则其时间复杂度为O(n)
序列排序前逆序:进行了n(n-1)/2次循环,则其时间复杂度为O(n^2)
则其平均时间复杂度为O(n^2)(2)空间复杂度:
只用了一个辅助单元r[0]/temp,则其空间复杂度为O(1)
(3)稳定性
稳定