1. Selection Sort
Algorithm:一个指针遍历数组,另一个指针遍历后面位置的值并找到最小值,与当前指针位置的值进行交换。时间复杂度O(N^2).
public void selectionSort(int[] a) {
int size = a.length;
for (int i = 0; i < size; i++) {
// 选择当前遍历到的点作为最小值
int min = i;
// 然后遍历后面的数,找到最小值,并且替换到当前位置
for (int j = i + 1; j < size; j++) {
if (less(a[j], a[min])) {
min = j;
}
// 注意这里替换的是min而不是j, 因为当取到最小值的时候,min并不会被j赋值,只有j位置比min小的时候,才会被赋值,所以j会在取到min之后再向后移动一次
exch(a, i, min);
}
}
}
(1) 无论input的order, 都是二次方的runtime
(2)不适用小的数据输入,因为每次都要进行exchange(线性复杂度)
2. Insertion Sort
Algorithm:把数组分为可见和不可见两部分,两个指针i和j,遍历到的是可见部分, 同时遍历数组,j从i的位置向后移动,如果比前一位小,那么交换位置。
public void sort(int[] a) {
int size = a.length;
for (int i = 0; i < size; i++) {
// j 从当前位置开始,向前遍历,如果j比前一位小,那么交换
for (int j = i; j > 0; j--) {
if (less(a[j], a[j-1])) {
exch(a, j, j-1);
}else {
// 如果j不比前面任意一个数小了,那么结束当前的for循环(因为前面的数组是有序的)
break;
}
}
}
}
**注意上面两个排序的数组int[] a 都是Comparable[] a, 即是具有比较性质的
((1/4 N^2) compares, and (1/4N^2) exchange)
** Worstcase, 如果数组是降序的,那么每一次都要移动到最前面,runtime θ(N^2), 每次只移动一个位置导致其效率不高
** 那么InsertionSort适用于什么情况呢?
适用于数组中有部分是排序的!!!(这种情况insertionSort的时间复杂度是Linear的)
3.ShellSort
Algorithm: 实际上就是InsertionSort的改良,InsertionSort是一次移动一个位置,Shell一次向前移动h个位置(j指针,i指针从h位置开始向后移动)。
适用情况:1. Linear time for almost-sorted array.
2. Small array (a couple of hundreds elements).
3. Some clever sorting algorithms perform amost-sorting and then let insertion sort take over.
Shell sort is a little bit better than insertion sort.
public void sort(int[] a) {
int size = a.length;
int h = 1;
// 最佳适用的h(来自于经验)
while (h < size/3) {
h = h*3 +1;
}
while (h >= 1) {
// 从h处开始遍历
for (int i = h; i < size; i++) {
// j 从h处向前遍历可见的部分, 并前每次移动h个位置,如果小于前面的,那么交换
for (int j = i; j >= h && less(a[j], a[j-h]); j = j - h) {
exchan(a, j , j-h);
}
}
h = h / 3;
}
}
**其实就是一点一点的排,对于不大的数组是有用的
4. Shuffling
public void sort(int[] a) {
int size = a.length;
for (int i = 0; i < size; i++) {
int random = StdRandom.uniform(i+1);
exch(a, i , r);
}
}
5. Convex Hull
public void sortConvextHull(Comparable[] p) {
Stack<Point> hull = new Stack<>();
// 根据y坐标排序
Arrays.sort(p, Point.Y_Order());
// 根据和p[0](也就是y坐标最小的点)的角度排序
Arrays.sort(p, p[0].polarOrder());
hull.push(p[0]);
hull.push(p[1]);
for (int i = 2; i < size; i++) {
// 弹出最后插入的角
Point top = hull.pop();
while (Point.ccw(hull.peek, top, p[i]) <= 0) {
// 当不是逆时针的时候,
// top 还是前面那个角
top = hull.pop();
}
// repush the top
hull.push(top);
hull.push(p[i]);
}
}
// counterclockwise
public static int ccw(Point a, Point b, Point c) {
double area2 = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
.......
// 只有大于零才是逆时针的
}