[TOC]

直接选择排序和折半插入排序比较次数与序列初始无关

insert Sorting

思想:V~0~,V~1~,…,V~i-1~个对象已排好序,现要插入V~i~到适当位置

直接插入排序

每次排序时保证前面的都有序,所以每次都只需要插入一个就好

public static void insertionSort(Comparable[] a){
	int j;
    Comparable tmp;
    for(int p = 0; p < a.length(); p++){
        Comparable tmp = a[p];
        for(j = p; j > 0 && tmp.CompareTo(a[j - 1]); j--){
            a[j] = a[j - 1];
        }
        a[j] = tmp;//找到要插入的地方哩
    }//每次循环保证前面的序列有序
}

一般情况:KCN = O(n^2^) RMN = O(n^2^)

稳定性:稳定的

Binary Insert Sort

改用二分法插入的”插入排序”

Public static void BinaryInsertSort(Comparable[] a){
    for(int p = 1; p < a.length(); p++){
        int left = 0;
        int right = p - 1;
        while(left <= right){
            int middle = (left + right) / 2;
            if(a[midddle].CompareTo(a[p]) > 0){
                right = middle - 1;
            }
            else{
                left = middle + 1;
            }
        }
        Comparable tmp = a[p];
        for(int k = p - 1; k >= left; k--){
            a[k + 1] = a[k];
        }
        a[left] = tmp;//left就是我要找的位置
    }
}

比较次数:O(n * log~2~n) 与初始序列无关

稳定性:稳定

Shell Sort

public static void shellsort(Comparable[] a){
    for ( int gap = a.length / 2; gap > 0; gap /= 2 )
        for ( int i = gap; i < a.length; i++ ){ 
            Comparable tmp = a[ i ];
            int j = i;
            for ( ; j >= gap && tmp.compareTo( a[ j- gap ] ) < 0; j -= gap )
                a[ j ] = a[ j  gap ];
            a[ j ] = tmp;
        }
}

不稳定

算法分析与gap选取有关

交换排序

方法的本质:不断的交换反序的对偶,直到不再有反序的对偶为止。

两种方法:

起泡排序(Bubble sort)

快速排序( Quick sort)

Bubble Sort

不是哥们,这还需要多说?

稳定性:最稳定的

比较次数*3是因为swapreference引入一个temp,实际上做了三次交换

Quick Sort

方法:

1)在n个对象中,取一个对象(如第一个对象——基准pivot),按该对象的关键码把所有<=该关键码的对象分划在它的左边。>该关键码的对象分划在它的右边。

2) 对左边和右边(子序列)分别再用快排序。

O(nlog~2~n)

随机取中值

不太好,具体步骤可以参考下面那个

三数中值分割法

CUTOFF 是一个用于决定何时应该切换到另一种排序算法的阈值。在快速排序中,当待排序的数组或数组的一部分(子数组)变得足够小的时候,使用插入排序可能会比继续使用快速排序更高效。这是因为插入排序对于小数组具有较低的 overhead,并且可以更有效地处理已经接近有序的数据。

这里的 CUTOFF 通常是一个预先定义的常量,用于确定这个切换点。例如,如果 CUTOFF 被设置为 10,那么当子数组的大小小于或等于 10 时,算法将使用插入排序而不是快速排序。

在代码中,left + CUTOFF <= right 这个条件检查当前子数组的大小是否小于或等于 CUTOFF。如果是,那么将使用插入排序来对这部分数组进行排序。

这种策略被称为“尾递归优化”或“小数组优化”,它可以提高排序算法在处理小数据集时的性能。插入排序在数据规模较小的情况下,由于其简单性和较低的递归调用开销,往往表现得比快速排序更好。

请注意,CUTOFF 的具体值可能因实现而异,需要根据实际情况进行调整,以达到最佳的性能。在 Java 的 Arrays.sort() 方法中,就使用了类似的策略,其中快速排序和插入排序相结合,以优化不同规模数据的排序性能。

public static void quicksort(Comparable[] a){
    quicksort(a, 0, a.length() - 1);
}

public static Comparable median3(Comparable[] a, int left, int right){
    int center = (left + right) / 2;
    if(a[center].compareTo(a[left] < 0)){
        swapReferences(a, left, center);
    }
    if(a[right].compareTo(a[left]) < 0){
        swapReferences(a, left, right);
    }
    if(a[right].compareTo(a[center]) < 0){
        sWapReference(a, center, right);
    }
    swapReference(a, center, right - 1);
    return a[right - 1];
}
public static void quicksort(Comparable[] a, int left, int right){
    if(left + CUTOFF <= right){
        Comparable pivot = median3(a, left, right);
        int i = left, j = right - 1;
        while(1){
            while(a[++i].compareTo(pivot) < 0){
            }
            while(a[--j].compareTo(pivot) > 0){
            }
            if(i < j){
                swapReferences(a, i, j);
            }
            else{
                break;
            }
        }
        swapReferecens(a, i, right - 1);//把pivot还回去
        quicksort(a, left, i - 1);
        quicksort(a, i + 1, right);
    }
    else{
        insertionSort(a, left, right);
    }
    //对于什么时候用quicksort什么时候用insertionsort我存疑
}

Selection Sort

直接选择排序

public static void SelectionSort(Comparable[] a){
    for(int i = 0; i < a.length() - 1; i++){
        int k = i;
        for(int j = i + 1; j < a.length(); j++){
            if(a[j].compareTo(a[k]) < 0){
                k = j;
            }
        }
        if(k != i){
            SwapReferences(k, i);
        }
    }
}

O(n^2^)

不稳定

树形选择排序(锦标赛排序)

详情见树章节的笔记

堆排序

详情见堆章节

不稳定

Merge Sort

归并

  public static void merge( Comparable [ ] a, Comparable [ ] tmpArray,int leftPos, int rightPos, int rightEnd ){
    int leftEnd = rightPos  1;
    int tmpPos = leftPos;
    int numElements = rightEnd  leftPos + 1;
    while( leftPos <= leftEnd && rightPos <= rightEnd )
        if( a[ leftPos ].compareTo( a[ rightPos ] ) <= 0 )
            tmpArray[ tmpPos++ ] = a[ leftPos++ ];
    	else tmpArray[ tmpPos++ ] = a[ rightPos++ ];
    while( leftPos <= leftEnd )
        tmpArray[ tmpPos++ ] = a[ leftPos++ ];
    while( rightpos <= rightEnd)
        tmpArray[ tmpPos++] = a[ rightpos++ ];
    for( int i = 0; i < numElements; i++, rightEnd-- )
        a[ rightEnd ] = tmpArray[ rightEnd ];
}

迭代的归并排序算法

非递归

public static void MergeSort(Comparable[] a){
    Comparable[] tmp = new Comparable[MaxSize];
    int len = 1;
    while(len < a.length()){
        MergePass(a, tmp, len);
        len *= 2;
        if(len >= a.length()){
            for(int j = 0; j < a.length(); j++){
                a[i] = tmp[i];
            }
        }
        else{
            MergePass(tmp, a, len);
            len *= 2;
        }
    }
}

public static void MergePass(Comparable[] init, Comparable[] merged, int len){
    int i = 0;
    while(i + 2 * len <= init.length() - 1){
        merge(init, merged,i, i + len - 1, i + 2 * len - 1);
        i += 2 * len;
    }
    if(i + len <= init.length() - 1){
        merge(init, merged, i, i + len - 1, init.length() - 1)
    }
    else{
        for(int j = i; j < init.length(); j++){
            merged[j] = init[j];
        }
    }
};

O(nlog~2~n)

稳定

递归的归并排序算法

public static void mergeSort( Comparable [ ] a ){ 
    Comparable [ ] tmpArray = new Comparable[ a.length ];
 	mergeSort( a, tmpArray, 0, a.length  1 );
} 
private static void mergeSort( Comparable [ ] a, Comparable [ ] tmpArray, int left, int right ){ 
    if( left < right ){ 
        int center = ( left + right ) / 2;
 		mergeSort( a, tmparray, left, center );
 		mergeSort( a, tmpArray, center + 1, right );
 		merge( a, tmpArray, left, center + 1, right );
	}
}

private static void merge( Comparable [ ] a, Comparable [ ] tmpArray,
                          int leftPos, int rightPos, int rightEnd ){
    int leftEnd = rightPos  1;
    int tmpPos = leftPos;
    int numElements = rightEnd  leftPos + 1;
    while( leftPos <= leftEnd && rightPos <= rightEnd )
        if( a[ leftPos ].compareTo( a[ rightPos ] ) <= 0 )
            tmpArray[ tmpPos++ ] = a[ leftPos++ ];
    	else tmpArray[ tmpPos++ ] = a[ rightPos++ ];
    while( leftPos <= leftEnd )
        tmpArray[ tmpPos++ ] = a[ leftPos++ ];
    while( rightpos <= rightEnd)
        tmpArray[ tmpPos++] = a[ rightpos++ ];
    for( int i = 0; i < numElements; i++, rightEnd-- )
        a[ rightEnd ] = tmpArray[ rightEnd ];
}

递归的表归并排序

public static void MergeSort(List L){
    List L1 = new List();
    if(L.first != null){
        if(L.first.link != null){
            divide(L, L1);
            MergeSort(L);
            MergeSort(L1);
            L - merge(L, L1);
        }
    }
}

public static List merge(List L1, List L2){
    Listnode p = L1.first;
    Listnode q = L2.first;
    Listnode r = new Listnode();
    List temp = new List();
    if(p == null || q == null){
        if(p != null){
            temp.first = p;
            temp.last = L1.last;
        }
        else{
            temp.first = q;
            temp.last = L2.last;
        }
    }
    else{
        if(p.data.compareTo(q.data) <= 0){
            r = p;
            p = p.link;
        }
        else{
            r = q;
            q = q.link;
        }
        temp.first = r;
        while(p != null && q != null){
            if(p,data.compareTo(q.data) <= 0){
                r.link = p;
                r = p;
                p = p.link;
            }
            else{
                r.link = q;
                r = q;
                q = q.link;
            }
        }
        if(p == null){
            r.link = q;
            temp.last = L2.last;
        }
        else{
            r.link = p;
            temp.last = L1.last;
        }
    }
    return tmp;
}

public static void divide(List L1, List L2){
    Listnode p = L.first;
    Listnode q = p.link;
    q = q.link;
    L2.last = L1.last;
    while(q != null){
        p = p.link;
        q = q.link;
        if(q != null){
            q = q.link;
        }
    }
    q = p.link;
    p.link = NULL;
    L1.last = p;
    L2.first = q;
}

内排序小结