经典插入排序
- 具体算法:
在数组中向前遍历每个元素,遍历时将这个元素插入到前面的序列中。
//代码清单:
//in java source code
for (int i = left, j = i; i < right; j = ++i) {
long ai = a[i + 1];
while (ai < a[j]) {
a[j + 1] = a[j];
if (j-- == left) {
break;
}
}
a[j + 1] = ai;
}
双点插入排序
向前遍历时每次遍历两个元素,两个元素先拍好次序,当较小的元素找到位置后,较大的元素在该位置之后查找位置,减少了第二个元素从头到尾注意比较的开销
//代码清单:
//in java source code
do {
if (left >= right) {
return;
}
} while (a[++left] >= a[left - 1]);
for (int k = left; ++left <= right; k = ++left) {
long a1 = a[k], a2 = a[left];
if (a1 < a2) {
a2 = a1; a1 = a[left];
}
while (a1 < a[--k]) {
a[k + 2] = a[k];
}
a[++k + 1] = a1;
while (a2 < a[--k]) {
a[k + 1] = a[k];
}
a[k + 1] = a2;
}
//由于是双点插入,一旦数组的长度是奇数,最后一个元素将没办法执行上面的for语句,因此需要对最后一个元素进行简单排序
long last = a[right];
while (last < a[--right]) {
a[right + 1] = a[right];
}
a[right + 1] = last;
}
二分插入排序:java.util.TimSort.binarySort
lo是需要排序的序列的起始索引号,hi是终止索引号,start是即将新插入的元素的索引号所以轴p为a[start],一开始的时候,left指向lo,right指向hi,mid=(left+right)/2,如果a[mid]<p,则交换。否则left++之后重新计算mid,再进行计算。该排序方法是稳定的。
private static <T> void binarySort(T[] a, int lo, int hi, int start,
Comparator<? super T> c) {
assert lo <= start && start <= hi;
if (start == lo)
start++;
for ( ; start < hi; start++) {
T pivot = a[start];
// Set left (and right) to the index where a[start] (pivot) belongs
int left = lo;
int right = start;
assert left <= right;
/*
* Invariants:
* pivot >= all in [lo, left).
* pivot < all in [right, start).
*/
while (left < right) {
int mid = (left + right) >>> 1;
if (c.compare(pivot, a[mid]) < 0)
right = mid;
else
left = mid + 1;
}
assert left == right;
int n = start - left; // The number of elements to move
// Switch is just an optimization for arraycopy in default case
switch (n) {
case 2: a[left + 2] = a[left + 1];
case 1: a[left + 1] = a[left];
break;
default: System.arraycopy(a, left, a, left + 1, n);
}
a[left] = pivot;
}
}