插入排序
情景:对数组 int[] arr = {6,9,5,2,8,7}中的数据 从小到大排序。
思路:在插入排序中,会有一个标记元素,该标记元素左侧的所有元素都是有序的,该元素及其右侧的元素都是无序的。所以在排序中,会将该被标记元素与它左侧的所有元素逐个比较,如果左侧的元素大于等于该被标记元素,则左侧的元素右移;直至不满足该条件为止,然后将标记元素插入左侧元素移动之前的位置。此时,第一趟排序已经完成。然后将被标记元素原来的位置+1,同理,开始第二趟排序。注意,红色元素为被标记元素。
第一趟排序前: 6 9 5 2 8 7 排序后:6 9 5 2 8 7
第二趟排序前: 6 9 5 2 8 7 排序后:5 6 9 2 8 7
第三趟排序前: 5 6 9 2 8 7 排序后:2 5 6 9 8 7
第四趟排序前: 2 5 6 9 8 7 排序后:2 5 6 8 9 7
第五趟排序前: 2 5 6 8 9 7 排序后:2 5 6 7 8 9
代码:
/** * 插入排序 * @author D N * */ public class InsertSort { private long[] a; private int nElems; public InsertSort(int max){ a = new long[max]; nElems = 0; } public void insert(long value){ a[nElems] = value; nElems++; } public void display(){ for(int j=0;j<nElems;j++){ System.out.print(a[j]+" "); } System.out.println(""); } //插入排序算法 public void insertSort(){ int in,out; for(out = 1;out < nElems;out++){ long temp = a[out]; //a[out]是被标记元素,将被标记元素赋予给一个临时变量temp in = out; //将被标记元素与它左侧的有序元素逐个比较, 如果左侧的元素大于等于被标记元素,则左侧的元素右移,直至不满足这个条件则停止比较移动,并将被标记元素放到这个位置 while(in > 0 && a[in-1] >= temp){ a[in] = a[in-1]; --in; } a[in] = temp; } } }
运行测试代码:
public class SortTest { public static void main(String[] args) { int maxSize = 10; InsertSort arr = new InsertSort(maxSize); arr.insert(6); arr.insert(9); arr.insert(5); arr.insert(2); arr.insert(8); arr.insert(7); arr.display(); arr.insertSort(); arr.display(); } }
运行结果:
6 9 5 2 8 7 2 5 6 7 8 9
效率分析:
在第一趟排序中,最多进行了1次比较,第二趟排序中最多进行了2次比较,所以最多进行了N*(N-1)/2次比较,在每趟排序中,发现插入点之前,平均只有一半的数据进行了比较 N*(N-1)/4。需要注意的是,插入排序中,是比较然后复制,而不是交换,复制消耗的时间比交换要少。虽然它的时间复杂度也是O(n2),但是它比冒泡排序要快一倍,比选择排序也快。插入排序应用比较多。