1.定义
(基本思想)每次将一个待排序的元素,按其关键字大小插入到已经排好序的子表中的适当位置,直到全部元素插入完成为止。
直接插入排序<<<
折半插入排序
希尔排序|
2.基本思路
step1:找插入位置
从第一个元素开始,找到第一个比待插入元素大的元素,
“插入位置”I
step2:插入操作
从最后面,一个一个元素往后挪
代码实现
#include <stdio.h>
#define N 10
/*
insert:把元素x,插入到升序数组a[]中去
a[0] a[1] ... a[n-1]
@a:数组名
@n:原有序表的元素个数,0,...,n-1
@x:待插入元素
返回值:
无返回
*/
void insert(int a[], int n, int x)
{
int i,j,k;
//step1:找插入位置
for(i = 0;i < n; i++)
{
if(a[i] > x)
{
break;
}
}
//i就是插入位置
//step: 插入操作(先挪后插入)
for(j = n-1; j >= i;j--)
{
a[j+1] = a[j];
}
a[i] = x;
}
//给数组a[n]进行 直接插入排序
void insertSort(int a[], int n)
{
int i;
for(i = 1; i < n; i++)
{
insert(a, i, a[i]);
}
}
int main()
{
int a[N];
int i;
for(i = 0;i < N; i++)
{
scanf("%d",&a[i]);
}
insertSort(a, N);
for(i = 0;i < N; i++)
{
printf("%d ",a[i]);
}
printf("\n");
return 0;
}
3.直接插入改进
“边比较边挪位置”
从最后面的元素,一个一个与待插入元素x比较
[ai] > x => 把[ai]往后挪
a[i+1]-a[i]
直到a[i] <= x此时i+1就是插入位置。
(1)龙哥改进版
#include <stdio.h>
#define N 5
/*
insert:把元素x,插入到升序数组a[]中去
a[0] a[1] ... a[n-1]
@a:数组名
@n:原有序表的元素个数,0,...,n-1
@x:待插入元素
返回值:
无返回
*/
void insert(int a[], int n, int x)
{
int i,j,k;
//debug
printf("\n------------------------------------\n");
for(i = 0; i < n; i++)
{
printf("%d ",a[i]);
}
printf(" \033[1;34m%d\033[0m\n",x); //高亮打印
for(k = n-1; k >= 0 && a[k] > x;k--)
{
a[k+1] = a[k];
}
a[k+1] = x; //k+1就是插入位置
//debug
printf("\n------------------------------------\n");
for(i = 0; i < n+1; i++)
{
if(i == k+1)
{
printf("\033[1;34m%d\033[0m ",a[i]); //高亮打印
}
else
{
printf("%d ",a[i]);
}
}
printf("\n------------------------------------\n");
}
//给数组a[n]进行 直接插入排序
void insertSort(int a[], int n)
{
int i;
for(i = 1; i < n; i++)
{
insert(a, i, a[i]);
}
}
int main()
{
int a[N];
int i;
for(i = 0;i < N; i++)
{
scanf("%d",&a[i]);
}
insertSort(a, N);
for(i = 0;i < N; i++)
{
printf("%d ",a[i]);
}
printf("\n");
return 0;
}
(2)改进版集成
#include <stdio.h>
#define N 5
void InsertSot(int a[] , int n)
{
int i,j;
for(i=1;i<n;i++)
{
for(j=i-1;j>=0 && a[j]>a[i];j--)
{
a[j+1] = a[j];
}
a[j+1] = a[i];
}
}
int main()
{
int a[N]={0};
int i;
for(i=0;i<N;i++)
{
scanf("%d",&a[i]);
}
InsertSot(a,N);
for(i=0;i<N;i++)
{
printf("%d",a[i]);
}
printf("\n");
return 0;
}
(3)课外集成版
/*插入排序是把一个记录插入到已排序的有序序列中,使整个序列在插入该记录后仍然有序。插入排序中较简单的种方法是直接插入排序,其插入位置的确定方法是将待插入的记录与有序区中的各记录自右向左依次比较其关键字值的大小。*/
/*基本有序,记录数少*/
/*
基本思想: 每一步将一个待排序的元素,按其排序码的大小,插入到前面已经排好序 的一组元素的合适位置上去,直到元素全部插完为止。
直接插入排序; 当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经 排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序 进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移
元素集合越接近有序,直接插入排序算法的时间效率越高 最优情况下:时间效率为O(n) 最差情况下:时间复杂度为O(n^2) 空间复杂度:O(1),它是一种稳定的排序算法
*/
#include <stdio.h>
void InsertSort(int k[], int n)
{
int i, j, temp;
for( i=1; i < n; i++ )
{
if( k[i] < k[i-1] )
{
temp = k[i];
for( j=i-1; k[j] > temp; j-- )
{
k[j+1] = k[j];
}
k[j+1] = temp;
}
}
}
int main()
{
int i, a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
InsertSort(a, 10);
printf("排序后的结果是:");
for( i=0; i < 10; i++ )
{
printf("%d", a[i]);
}
printf("\n\n");
return 0;
}
4.直接插入排序的性能分析
(1)时间复杂度
a.最坏情况
每次来的都是“最小元素” “反序”
O(n2)
b.最好情况
每次来的都是”最大元素” 正序
O(n)
c.平均情况
O(n2)
(2)空间复杂度
O(1)
5.直接插入排序稳定性分析
直接插入排序 是 稳定的。
6.总结
1.插入排序在对几乎已经排好序的数据操作时,效率高,可以达到线性排序的效率。O(n)
但
2.插入排序一般来说是低效的,因为插入排序每次只能将数据移动一个位置。
适用场景
插入排序由于O( n2 )的复杂度,在数组较大的时候不适用。但是,在数据比较少的时候,是一个不错的选择,一般做为快速排序的扩充。例如,在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充,用于少量元素的排序。又如,在JDK 7 java.util.Arrays所用的sort方法的实现中,当待排数组长度小于47时,会使用插入排序。