目录
1.直接插入排序
它的基本思想是:仅有一个元素的序列总是有序的,因此,对 n 个记录的序列,可从第二个元素开始直到第 n 个元素,逐个向有序序列中执行插入操作,从而得到 n 个元素按关键字有序的序列。假如前 j-1 个元素是有序的,那么第 j 个元素的插入位置为:前 j-1 个元素中第一个不大于第 j 个元素的元素,第 j 个元素插入到该元素之前,后面的元素依次后移一位。
Java实现代码如下:
public static void simpleInsertSort(int arr[]) {
int temp;
for(int i = 1;i < arr.length;i++) {
temp = arr[i];
int j = i-1;
for(;j >= 0 && arr[j] > temp;j--)
arr[j+1] = arr[j];
arr[j+1] = temp;
}
}
2.二分(折半)插入排序
直接插入排序的基本操作是向有序序列中插入一个元素,插入位置的确定是通过对有序序列中元素按关键字逐个比较得到的。既然是在有序序列中确定插入位置,则可以不断二分有序序列来确定插入位置,即搜索插入位置的方法可以使用折半查找实现。
Java实现代码如下:
public static void binaryInsertSort(int arr[]) {
int temp, left, right, mid;
for(int i = 1;i < arr.length;i++) {
temp = arr[i];
left = 0;
right = i - 1;
mid = ( left + right ) / 2;
while(left <= right) {
if(arr[mid] <= temp) left = mid + 1;
else right = mid -1;
mid = ( left + right ) / 2;
}
for(int j = i-1;j > right;j--)
arr[j+1] = arr[j];
arr[right+1] = temp;
}
}
3.希尔排序(缩小增量排序)
希尔排序又称为“缩小增量排序”,它也是一种属于插入排序类的排序方法,是一种对直接插入排序的改进,但在时间效率上却有较大的改进。 从对直接插入排序的分析中知道,虽然直接插入排序的时间复杂度为O(n2),但是在待排序元素序列有序时,其时间复杂度可提高至O(n)。由此可知在待排序元素基本有序时,直接插入排序的效率可以大大提高。
希尔排序的基本思想是:首先将待排序的元素分为多个子序列,使得每个子序列的元素个数相对较少,对各个子序列分别进行直接插入排序,待整个待排序序列“基本有序”后,再对所有元素进行一次直接插入排序。希尔排序的关键在于选择一个步长序列t1,t2,…,tk,其中ti>tj(i<j),tk=1;然后进行k次直接插入排序就可以了,比如一个待排序序列arr={9,8,7,6,5,4,3,2,1,0},选择步长序列delta={4,2,1},那么第一趟直接插入排序可以快速将9移动至arr[9]的位置,1移动至arr[0]的位置,解决了限制插入排序时间效率的关键,即极端情况下寻找插入位置极为耗时。
Java实现代码如下:(注,代码选择的步长序列为{arr.length/2, arr.length/(2*2),……,1},其实可以自己指定。希尔排序的时间复杂度与步长序列的选取密切相关,如何选择步长序列才能使得希尔排序的时间复杂度达到最佳,这还是一个有待解决的题。)
public static void shellSort(int arr[]) {
int temp;
for(int len = arr.length / 2;len >= 1;len = len /2 ) {//len为步长
for(int i = len;i < arr.length;i = i++) {
temp = arr[i];
int j = i - len;
for(;j >= 0 && arr[j] > temp;j = j - len)
arr[j+len] = arr[j];
arr[j+len] = temp;
}
}
}
4.总结
直接插入排序和二分插入排序的平均时间复杂度都是O(n2),且都是一种稳定的排序算法,希尔排序的时间复杂度与选取的步长序列有关,不稳定。
下面我用含有10万个随机元素的整形数组对数组的时间效率进行了测试,可以发现如理论分析所述,时间效率simpleInsertSort<binaryInsertSort<shellSort。