选择排序
定义:每次迭代过程中,我们都是从剩余元素(remaining entries)中选得最小的元素放在对应的位置上,这里的不变量(invariant)为左边已经排好序的部分。
特点:比較次数是 N(N-1)/2 交换次数是 N (each exchange puts an item into its final position, so the number of exchanges is N. Thus, the running time is dominated by the number of
compares)。数学模型是上三角。每一次寻找最小元素的过程不会为下一趟的寻找提供额外信息。所以对于一个有序的数组。仍然要花和一个随机数组一样长的时间;选择排序中数组訪问是和数组尺寸线性相关的,这是其它排序不具有的。
实现:
public class SelectionSort
{
// This
class should not be instantiated.
private SelectionSort()
{
}
// ascending
order
public static void sort(Comparable[]
a) {
int N
= a.length ;
for (int i
= 0; i < N; i++) {
int min
= i;
for (int j
= i + 1; j < N; j++) {
if (less(a[j],
a[min]))
min = j;
}
exch(a, i, min);
assert isSorted(a,
0, i);
}
assert isSorted(a);
}
/***********************************************************************
* Helper sorting functions
***********************************************************************/
// is
v < w ?
private static boolean less(Comparable v, Comparable w)
{
return (v.compareTo(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;
}
/***********************************************************************
* Check if array is sorted - useful
for debugging
***********************************************************************/
// is
the array a[] sorted?
private static boolean isSorted(Comparable []
a) {
return isSorted(a,
0, a. length - 1);
}
// is
the array sorted from a[lo] to a[ hi]
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 ;
}
// print
array to standard output
private static void show(Comparable[]
a) {
for (int i
= 0; i < a.length; i++) {
System. out.print(a[i]
+ " " );
}
}
public static void main(String[]
args) {
Integer[] a = { 10, 45, 0, 8, 7, -34, 20 };
SelectionSort. sort(a);
show(a);
}
}
插入排序
定义:能够联系到扑克牌,每次都是将一个数字插入到一个有序序列的合适位置。为了给其腾出空间。须要后移比他大的元素。
特点:尽管在当前元素(current index)左边都是有序的,可是却不是他们的终于位置;对于一个随机数组,如果每次在插入一个元素时都是移动一半。则#compare=N^2/4。#exchange=N^2/4。最坏情况是每次都是插入到第一个位置(和选择排序一样了)是N^2/2。最好情况是已经有序,仅仅须要比較N-1次。
假设数组中倒置的数量小于数组大小的常数倍数,那么称这种数组是部分有序的。插入排序对于这种数组非常有效。(倒置是一个序列中乱序的键值对的个数,比方AEDC中的倒置有E-D,E-C,D-C,也就是须要变换位置的pair)
实现:
public class InsertionSort
{
//其它代码同上
// ascending
order
public static void sort(Comparable[]
a) {
int N
= a.length ;
for (int i
= 0; i < N; i++) {
for (int j
= i; j > 0 && less (a[j], a[j - 1]); j--) {
exch(a, j, j - 1);
}
}
}
}
希尔排序
定义:对于大规模乱序数组插入排序非常慢,由于它仅仅交换相邻的元素。所以元素仅仅能一步步的从这一端移动到还有一端;希尔排序在插入排序的基础上做了改进。先对几个交错的序列进行局部排序(比方步长是h的子数组)这样加快了元素交换的速度,没一次的h-sort都会使得数组越来越有序,然后逐渐改变增长序列。直到终于得到有序数组。希尔排序在数组的尺寸和部分有序直接做了权衡。部分有序的程度取决于增长序列。
特点:至今没有发现一个最优的增量序列,使用递增序列(3x+1) 1, 4, 13, 40, 121, 364…的希尔排序所需的比較次数不会超出 N 的若干倍乘以递增序列的长度。
在这个增量序列下。shellsort最多比較次数是N^(3/2).
实现:
public class ShellSort
{
// This
class should not be instantiated.
private ShellSort()
{
}
// ascending
order
public static void sort(Comparable[]
a) {
int N
= a.length ;
int h =
1;
//
找到最大的步长
while (h <
N / 3)
h =
3 * h + 1; // 1,4,13,40
while (h >=
1) {
//
用不同的增量来对子数组插入排序
for (int i
= h ; i < N; i += h) {
for (int j
= i; j > 0 && less (a[j], a[j - h]); j -= h )
{
exch(a, j, j
- h );
}
}
h /=
3;
}
}
}
Shuffle Sort
这里是利用排序的场景,洗牌算法
1.为每一张牌随机产生不同的数,而后利用上述的排序算法;
2.In iteration i, pick integer r between 0 and i uniformly at random. then Swap a[i] and a[r].(这是Knuth发明的)显然是线性复杂度。
实现:
public class TestShuffle
{
private static void exch( int[]
a, int i, int j)
{
int swap
= a[i];
a[i] = a[j];
a[j] = swap;
}
public static void shuffle( int[]
a) {
int N
= a.length ;
for (int i
= 0; i < N; i++) {
int r
= StdRandom.uniform(i + 1); // 在 1-i之间产生随机数
exch(a, i, r);
}
}
public static void main(String[]
args) {
int []
test = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
shuffle(test);
for (int i
= 0; i < test. length; i++)
System. out .print(test[i]
+ " " );
}
}
归并排序
定义:利用分治思想,将大问题划分为小问题,然后进行合并。
特点:最大的长处是NlgN的复杂度(能够通过公式推导,或画递归树得到)
实现:
public class MergeSort
{
private static Comparable[] aux; //
辅助数组
// This class should not be instantiated.
private MergeSort()
{
}
public static void sort(Comparable[]
a) {
aux = new Comparable[a.length];
sort(a, 0, a.length -
1);
}
// 递归子例程
private static void sort(Comparable[]
a, int lo, int hi)
{
if (hi
<= lo)
return;
int mid
= lo + (hi - lo) / 2;
sort(a, lo, mid);
sort(a, mid + 1, hi);
merge(a, lo, mid, hi);
}
// in-place merge , not to get an output array
public static void merge(Comparable[]
a, int lo, int mid, int hi)
{
int i
= lo, j = mid + 1, k;
for (k
= lo; k <= hi; k++)
aux[k]
= a[k];
// merge back to the original array a[lo.....hi]
for (k
= lo; k <= hi; k++) {
if (i
> mid) // left is over
a[k] = aux[j++];
else if (j
> hi) // right is over
a[k] = aux[i++];
else if (less( aux[i],
a[j]))
a[k] = aux[i++];
else
a[k] = a[j++];
}
}
}