一、插入排序
基本思想:把一个数组划分为两部分,一个有序,一个无序,每次从无序列当中取出一个插入到有序列中的正确位置。插入排序的最优的时间复杂度是O(n), 最差的时间复杂度O(n^2) ,平均时间复杂度O(n^2),空间复杂度为O(1),是稳定排序。
伪代码:
for i=1 to A.length-1 key=A[i] j=i-1 while j>=0 and key<A[j] A[j+1]=A[j] j=j-1 A[j+1]=key
java代码:
public static void insertSort(int A[]){ for(int i = 1; i < A.length; i++){ int key = A[i]; int j = i-1; while(j >= 0 && key < A[j]){ A[j+1] = A[j]; j--; } A[j+1] = key; } }
二、希尔排序
基本思想:当原始序列基本有序或原序列长度较小时,插入排序的性能非常好,但是现实中的排序不可能满足这么苛刻的条件,因此我们可以做如下改进:将原来的大量数据进行分组,这样每次只在元素数量较少的序列上进行插入排序,当完成分组的排序后,整个序列基本有序,这样再进行插入排序速度会很快。一次插入排序是稳定的,但是在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,稳定性被破坏。希尔排序的时间复杂度为O(n^3/2),优于快速排序。
java代码:
public static void shellSort(int A[]){ int d = A.length/2; while(d > 0){ for(int x = 0; x < d; x++){ for(int i = x+d; i < A.length; i += d){ int key = A[i]; int j = i-d; while(j >= 0 && key < A[j]){ A[j+d] = A[j]; j -= d; } A[j+d] = key; } } d/=2; } }
三、二分插入排序
基本思想:该排序是插入排序的延伸,只是先利用二分查找判断该元素应该插入的位置。
这里我们先介绍简单的二分查找:
java代码:
public static int BinarySearch(int A[],int low,int high,int value){ while(low <= high){ int mid = (low + high)/2; if(A[mid] > value) high = mid - 1; else if(A[mid] < value) low = mid + 1; else return mid; } return -1; }
但是在二分查找排序中我们不一定要找到跟要插入的值相同的那个值,而是要找到一个位置,处于该位置左边的值都不大于该值,也就是找到这个值在已排序数列中的“上界”。找到该位置后,对该位置之后的值进行移位,然后将要插入的值放在该位置即可。
java代码:
public static int BSearchUpperBound(int array[], int low, int high, int value) { if(low > high) return -1; if(value >= array[high]) return (high + 1); int mid = (low + high) / 2; while (high > low) { if (array[mid] > value) high = mid; else low = mid + 1; mid = (low + high) / 2; } return mid; }