(稳定性就是俩个相同的元素排序前和排序后的相对位置,若相对位置不变,称为稳定)
直接插入排序-原理:(稳定)
整个区间被分为
- 有序区间 [0~index]
- 无序区间 (index~last]
每次选择无序区间的第一个元素array[indxe],在有序区间内选择合适的位置插入。
实现:
//降序直接插入排序
public static void inDownSort(int[] array) {
for (int index = 1; index < array.length; index++) {
int tmp = array[index];
for (int prevIndex = index - 1; prevIndex >= 0; prevIndex--) {
//若要升序直接改为:tmp < array[prevIndex]
if(tmp > array[prevIndex]) {
array[prevIndex + 1] = array[prevIndex];
array[prevIndex] = tmp;
}else {
break;
}
}
}
}
性能分析:
时间复杂度:
最好O(n)
平均O(n^2)
最坏O(n^2)
空间复杂度:
O(1)
== 希尔排序-原理 :(不稳定)==
希尔排序法又称缩小增量法。希尔排序法的基本思想是:
先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。
- 希尔排序是对直接插入排序的优化。
- 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
实现:
//降序希尔排序
public static void shellDownSort(int[] array) {
int gap = array.length / 2;
while (gap >= 1) {
for (int index = gap; index < array.length; index++) {
int tmp = array[index];
for(int prevIndex = index - gap; prevIndex >= 0; prevIndex -= gap) {
//若要升序直接改为:tmp < array[prevIndex]
if(tmp > array[prevIndex]) {
array[prevIndex + gap] = array[prevIndex];
array[prevIndex] = tmp;
}else {
break;
}
}
}
gap /= 2;
}
}
性能分析:
时间复杂度:
最好O(n)
平均O(n^1.3)
最坏O(n^2)
空间复杂度:
O(1)
折半插入排序-原理:(稳定)
在有序区间选择数据应该插入的位置时,因为区间的有序性,可以利用折半查找的思想。
仔细来说就是在while循环里找到合适的位置放此时index下标的值。
然后将low下标之后indxe之前的元素往后移动一个位置,最后在low下标放tmp。
实现:
//降序折半插入排序
public static void inHalfDownSort(int[] array) {
for (int index = 1; index < array.length; index++) {
int tmp = array[index];
int low = 0;
int high = index;
//与折半查找不同的是,折半查找这里是low<=high
while (low < high) {
int mid = (low + high) / 2;
//若要升序直接改为:array[mid] <= tmp
if(array[mid] >= tmp) {
low += mid + 1;
}else {
high = mid;
}
}
for (int i = index; i > low; i--) {
array[i] = array[i - 1];
}
array[low] = tmp;
}
}
执行结果:
[9, 8, 6, 4, 3]