一、定义
1.1 说明
图解:
描述:
对N个元素的数组进行插入排序,它将有N-1次排序完成。其原理也很简单:从第二个元素开始对每一个元素进行排序,即p=1开始,对每一位置p上的元素与前0到p上的元素对比,将p放入合适的位置。所以第p趟排序时,位置p前面的元素已经排序好了。只需要将p上的元素插入到一个已经排序的合适的位置。
做法:将p上的元素向左移动到x,直到位置x-1的元素比它小,x+1上的元素比它大。
例如数组a[]={34,8,64,51,32,21}。我们从p=1开始进行排序,将a[p]元素左移,直到它在合适的位置。
p=1时,对8进行排序:8,34,64,51,32,21;
p=2时,对64进行排序:8,34,64,51,32,21;
p=3时,对51进行排序:8,34,51,64,32,21;
p=4时,对32进行排序:8,32,34,51,64,21;
p=5时,对21进行排序:8,21,32,34,51,64;
1.2 算法分析
很明显,根据前面的描述,定义p为索引位置,当p=1时,最多需要用到1次比较,p=2时,最多需要2次比较。一直到p=N-1。所以总的比较次数最多:
[sum_{i=2}^{N}i=1+3+···+(N-1)=Theta(N^2)
]
由于插入排序的性质:将p放入前面已经排序的数组片段中。所以,输入几乎被排序的数组,插入排序会运行得很快。
Java代码
/**
* 插入排序
*
* @Author: dhcao
* @Version: 1.0
*/
public class InsertionSortEx<T extends Comparable<? super T>> {
/**
* 直接对数组a进行排序
*
* @param a 需要排序数组
* @param <T> 实现Comparable接口对类型
*/
public static <T extends Comparable<? super T>> void insertionSort1(T[] a) {
// 技巧1:在循环中重复定义的函数,可以放到循环外定义。
int j;
/**
* 从位置p=1开始,对所有对数组元素进行排序
*/
for (int p = 1; p < a.length; p++) {
// 提前将排序的元素a[p]准备好
T tmp = a[p];
// 将位置p上的元素向左边移动(即p左边的元素向右移动)(由于左边从0到p-1的元素已经在排序状态)
for (j = p; j > 0 && tmp.compareTo(a[j - 1]) < 0; j--) {
// 技巧2:将必须的操作留在循环中,不需要的操作可以移到循环外
a[j] = a[j - 1];
}
a[j] = tmp;
}
}
/**
* 将数组中的某一段进行排序。
* @param a 数组
* @param left 需要排序的左界
* @param right 需要排序的右界
* @param <T> 实现Comparable接口对类型
*/
public static <T extends Comparable<? super T>> void insertionSort2(T[] a,int left,int right){
int j;
for (int p = left + 1; p <= right; p++) {
T tmp = a[p];
for (j = p; j > 0 && tmp.compareTo(a[j - 1]) < 0; j--) {
a[j] = a[j - 1];
}
a[j] = tmp;
}
}
}