算法说明
通常人们整理桥牌的方法是一张一张的来,将每一张牌插入到其他已经有序的牌中的适当位置。
在计算机的实现中,为了给要插入的元素腾出空间,我们需要将其与所有的元素在插入之前都向右移动一位。
算法复杂度
对于随机排列的长度为N且主键不重复的数组,平均情况下插入排序需要~ N²/4次比较以及~ N²/4次交换。最坏情况下需要~ N²/2次比较和~ N²/2次交换,最好情况下需要N-1次比较和0次交换。
源代码
package edu.princeton.cs.algs4;
import java.util.Comparator;
public class Insertion {
private Insertion() { }
/**
* Rearranges the array in ascending order, using the natural order.
* @param a the array to be sorted
*/
public static void sort(Comparable[] a) {
int n = a.length;
for (int i = 1; i < n; i++) {
for (int j = i; j > 0 && less(a[j], a[j-1]); j--) {
exch(a, j, j-1);
}
assert isSorted(a, 0, i);
}
assert isSorted(a);
}
/**
* Rearranges the subarray a[lo..hi) in ascending order, using the natural order.
* @param a the array to be sorted
* @param lo left endpoint (inclusive)
* @param hi right endpoint (exclusive)
*/
public static void sort(Comparable[] a, int lo, int hi) {
for (int i = lo + 1; i < hi; i++) {
for (int j = i; j > lo && less(a[j], a[j-1]); j--) {
exch(a, j, j-1);
}
}
assert isSorted(a, lo, hi);
}
/**
* Rearranges the array in ascending order, using a comparator.
* @param a the array
* @param comparator the comparator specifying the order
*/
public static void sort(Object[] a, Comparator comparator) {
int n = a.length;
for (int i = 1; i < n; i++) {
for (int j = i; j > 0 && less(a[j], a[j-1], comparator); j--) {
exch(a, j, j-1);
}
assert isSorted(a, 0, i, comparator);
}
assert isSorted(a, comparator);
}
/**
* Rearranges the subarray a[lo..hi) in ascending order, using a comparator.
* @param a the array
* @param lo left endpoint (inclusive)
* @param hi right endpoint (exclusive)
* @param comparator the comparator specifying the order
*/
public static void sort(Object[] a, int lo, int hi, Comparator comparator) {
for (int i = lo + 1; i < hi; i++) {
for (int j = i; j > lo && less(a[j], a[j-1], comparator); j--) {
exch(a, j, j-1);
}
}
assert isSorted(a, lo, hi, comparator);
}
// return a permutation that gives the elements in a[] in ascending order
// do not change the original array a[]
/**
* Returns a permutation that gives the elements in the array in ascending order.
* @param a the array
* @return a permutation {@code p[]} such that {@code a[p[0]]}, {@code a[p[1]]},
* ..., {@code a[p[n-1]]} are in ascending order
*/
public static int[] indexSort(Comparable[] a) {
int n = a.length;
int[] index = new int[n];
for (int i = 0; i < n; i++)
index[i] = i;
for (int i = 1; i < n; i++)
for (int j = i; j > 0 && less(a[index[j]], a[index[j-1]]); j--)
exch(index, j, j-1);
return index;
}
/***************************************************************************
* Helper sorting functions.
***************************************************************************/
// is v < w ?
private static boolean less(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
// is v < w ?
private static boolean less(Object v, Object w, Comparator comparator) {
return comparator.compare(v, w) < 0;
}
// exchange a[i] and a[j]
private static void exch(Object[] a, int i, int j) {
Object swap = a[i];
a[i] = a[j];
a[j] = swap;
}
// exchange a[i] and a[j] (for indirect sort)
private static void exch(int[] a, int i, int j) {
int swap = a[i];
a[i] = a[j];
a[j] = swap;
}
/***************************************************************************
* Check if array is sorted - useful for debugging.
***************************************************************************/
private static boolean isSorted(Comparable[] a) {
return isSorted(a, 0, a.length);
}
// is the array a[lo..hi) sorted
private static boolean isSorted(Comparable[] a, int lo, int hi) {
for (int i = lo + 1; i < hi; i++)
if (less(a[i], a[i-1])) return false;
return true;
}
private static boolean isSorted(Object[] a, Comparator comparator) {
return isSorted(a, 0, a.length, comparator);
}
// is the array a[lo..hi) sorted
private static boolean isSorted(Object[] a, int lo, int hi, Comparator comparator) {
for (int i = lo + 1; i < hi; i++)
if (less(a[i], a[i-1], comparator)) return false;
return true;
}
// print array to standard output
private static void show(Comparable[] a) {
for (int i = 0; i < a.length; i++) {
StdOut.println(a[i]);
}
}
/**
* Reads in a sequence of strings from standard input; insertion sorts them;
* and prints them to standard output in ascending order.
*
* @param args the command-line arguments
*/
public static void main(String[] args) {
String[] a = StdIn.readAllStrings();
Insertion.sort(a);
show(a);
}
}
算法分析
程序输入来自tiny.txt,内容为
S O R T E X A M P L E
程序入口:
public static void main(String[] args) {
String[] a = StdIn.readAllStrings();
Insertion.sort(a);
show(a);
}
逻辑分析:
public static void sort(Comparable[] a) {
int n = a.length;
for (int i = 1; i < n; i++) {
// 第一次循环拿第二个数和第一个数比较
for (int j = i; j > 0 && less(a[j], a[j-1]); j--) {
//第二次循环拿第三个数和第二个数比较,再与第一个数比较
exch(a, j, j-1);
// 第三次循环拿第四个数和第三个数比较再与第二个数比较再与第一个数比较
// 最坏的情况就是每次都要交换,最好的情况就是每次都不用交换
}
assert isSorted(a, 0, i);
}
assert isSorted(a);
}
算法特点
- 倒置指数组中的两个顺序颠倒的元素。
- 如果数组中倒置的数量小于数组大小的某个倍数,那么我们说这个数组是部分有序的。
- 几种典型的部分有序数组:
- 数组中的每个元素距离它的最终位置都不远。
- 一个有序的大数组接一个小数组。
- 数组中只有几个元素的位置不正确。
- 以上数组,插入排序很有效,而选择排序则不然。事实上,当倒置的数量很少时,插入排序可能是最好的算法。
网友评论