java 通配符的應用— java 排序算法

  這幾天無聊,又從新學起java的排序算法,爲DualPivotQuickSort作準備。爲了更好地適應各類狀況,咱們選擇使用通用類型T和通配符的上下界來實現,同時此次談的是對數組對象的排序。若是你對java 通配符的瞭解不深的,能夠點擊 這裏 。
java

    如今假設有以下排序方法:算法

public static <T> void sort(T[] a, int n)

    由於對象之間能夠比較大小,數組對象必須是實現Comparable接口的。所以T所表示的類必須實現接口Comparable。爲此須要爲T添加一個上界,以下:shell

public static <T extends Comparable<T>> void sort(T[] a, int n)

    如此,便指定了傳遞給Sort的對象數組必須是可比較的.爲了sort()方法能夠更加貼近實際的須要,如今再作一點改進.api

    如今使用sort()方法對10個Integer對象排序以下:數組

sort(intArray,10);

    代碼」T extends Comparable<T>「要求Integer必須實現Comparable<Integer>,而且數組內的對象都必須是Integer對象。詳細的使用細則,可參考 java 通配符解惑。    T的對象不只能夠與T的其餘對象相互比較,也應該能夠與T的超類對象相比較。所以,取代」T extends Comparable<T>「的另外一種寫法是:數據結構

public static <T extends Comparable<? super T>> void sort(T[] a, int n)

             「?」表明任意類型,而「? super T」則意味着T的任意超類。寫成Comparable<? super T>,就能夠對任意類型使用Comparable。app

1、選擇排序:

    選擇排序是最基本的排序算法 ,通常不怎麼用,可倒是學排序最基本的算法,瞭解一下總無害。性能

    迭代僞代碼:ui

for i = 0:n-1,
    k = i    for j = i+1:n-1, if a[j] < a[k], k = j    //a[k] 老是a[i..n]最小的那一個
    swap a[i,k]    //排序的最後結果:a[1..i]end

性能:spa

    最壞的狀況:О(n2)

    最好的狀況:О(n2)

    平均情況:О(n2)

    不穩定

    額外須要的空間:O(n)

java 實現:

public static <T extends Comparable<? super T>> void selectionSort(T[] a){        int smallestIndex;        for(int i = 0;i < a.length; i++){
            smallestIndex = i;            for (int j = i+1; j < a.length; j++) {                if (a[j].compareTo(a[smallestIndex]) < 0) {
                    smallestIndex = j;
                }
            }
            swap(a, i, smallestIndex);
        }
    }private static void swap(Object[] a, int i, int j) {
        Object temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

  2、插入排序

    插入排序在最壞狀況下的效率是O(n2)。在大部分元素已排好序或者排序的元素數量少的狀況下,通常選擇使用插入排序(由於它是低開銷)。

    僞代碼:

for i = 1:n,    for (k = i; k > 0 and a[k] < a[k-1]; k--) 
        swap a[k,k-1]
end

性能(效率):

    最壞的狀況:О(n2)比較,О(n2)交換

    最好的狀況:O(n) 比較, O(1) 交換

    平均情況:О(n2)比較,О(n2)交換

    穩定

    額外須要的空間:O(n)

      

java 實現:

public static <T extends Comparable<? super T>> void insertionSort(T[] a) {        int len = a.length;        for (int i = 1; i < len; i++) {            for (int k = i; (k > 0) && (a[k].compareTo(a[k - 1]) < 0); k--) {
                swap(a, k, k - 1);
            }
        }
    }

3、冒泡排序

    冒泡排序與插入排序有不少類似的地方,只不過是冒泡排序的開銷稍高。

    僞代碼:

for i = 0:n-1,
    swapped = false
    for j = n-1:i+1, 
        if a[j] < a[j-1], 
            swap a[j,j-1]
            swapped = true
    break if not swapped
end

性能:

    最壞的狀況:О(n2)

    最好的狀況O(n)

    平均情況:О(n2)

    穩定

    額外須要的空間:O(n)

java實現:

 public static <T extends Comparable<? super T>> void bubbleSort(T[] a) {        boolean swapped;        for (int i = 0; i < a.length; i++) {
            swapped = false;            for (int j = a.length - 1; j > i; j--) {                if (a[j].compareTo(a[j - 1]) < 0) {
                    swap(a, j, j - 1);
                    swapped = true;
                }
            }            if (!swapped) { break; }
        }
    }

4、希爾排序

    希爾排序屬於插入類排序,是將整個無序列分割成若干小的子序列分別進行插入排序。將要排序的一組數按某個增量 gap 分紅 gap 組,每組中記錄的下標相差 gap.對每組中所有元素進行排序,而後再用一個較小的增量對它進行,在每組中再進行排序。當增量減到1時,整個要排序的數被分紅一組,排序完成。

性能:

    最壞的狀況:取決於增量(在這裏的基底是3)

    最好的狀況:取決於增量

    平均情況:取決於增量

    不穩定

    額外須要的空間:O(n)

java實現:

public static <T extends Comparable<? super T>> 
                           void shellSort(T[] a) {        for(int inc = a.length/3; inc > 0; inc /= 3){            for(int index = 0;index < inc; index++){
                shellInsertSort(a, index, inc);
            }
        }
        shellInsertSort(a, 0, 1);
    }    private static <T extends Object & Comparable<? super T>> 
              void shellInsertSort(T[] a, int start, int inc) {        //插入排序
        for(int i = start + inc;i < a.length; i += inc){            for(int index = i;(index >= inc) && (a[index]).compareTo(a[index - inc]) < 0;index -= inc){
                swap(a, index, index - inc);
            }
        }
    }

5、歸併排序

    歸併(Merge)排序法是將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分爲若干個子序列,每一個子序列是有序的。而後再把有序子序列合併爲總體有序序列。

僞代碼:

//將序列分半mid = n / 2//遞歸排序sort a[1..mid]
sort a[mid+1..n]//合併已排好序的子序列b = copy of a[1..m]
low = 1, high = mid+1, 
for cur= l:r   if(high > r) || low < mid + 1 && b[low] < b[high])
     a[cur] =b[low++]   else
     a[cur] =b[high++]

性能:

    最壞的狀況:O(n log n)

    最好的狀況:O(n log n)

    平均情況:O(n log n)

    穩定

    額外須要的空間:O(n)

java 實現:

    public static <T extends Comparable<? super T>> void mergeSort(T[] a) {
        T[] tempArray = (T[]) new Comparable<?>[a.length];
        mergeSortHelp(a, tempArray, 0, a.length - 1);
    }    private static <T extends Comparable<? super T>> 
        void mergeSortHelp(T[] a, T[] tempArray, int l, int r) {        int mid = (l + r) >>> 1;        if (l == r) {            return;
        }
        mergeSortHelp(a, tempArray, l, mid);
        mergeSortHelp(a, tempArray, mid + 1, r);
        System.arraycopy(a, l, tempArray, l, r - l + 1);        int low = l;        int high = mid + 1;        for (int cur = l; cur <= r; cur++) {            if ((high > r) || low < mid + 1 && (tempArray[low].compareTo(tempArray[high]) < 0)) {
                a[cur] = tempArray[low++];
            } else {
                a[cur] = tempArray[high++];
            }
        }
    }

6、堆排序

    堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序算法,能夠利用數組的特色快速定位指定索引的元素。堆排序(heapSort)主要分爲兩個步驟:第一步,根據初始數據,利用堆的調整算法 siftdown()造成初始堆;第二步,反覆地移除堆中最大的數據(將其插入數組裏),移除以後再繼續對利用堆的調整算法對剩下的數據進行調整。

僞代碼:

function heapSort(a, count) 
     heapify(a, count)//造成初始堆(大根堆) 
     end := count-1 //子女元素的索引爲 2*i+1 and 2*i+2
     while end > 0 
         swap(a[end], a[0]) //交換堆中最大的元素
         end := end - 1 //減小堆中元素的個數,從新調整爲大根堆
         siftDown(a, 0, end)          
function heapify(a, count)
     start := (count - 2 ) / 2 //將start做爲根節點   
     while start ≥ 0 
         siftDown(a, start, count-1)
         start := start - 1
function siftDown(a, start, end) is
     root := start     while root * 2 + 1 ≤ end do          //有子節點
         child := root * 2 + 1        //左子節點
         swap := root        //暫存子樹根節點)
         if a[swap] < a[child] //判斷根節點與左子節點的大小
             swap := child         //若是存在右子節點,則比較兩子節點的大小
         if child+1 ≤ end and a[swap] < a[child+1]
             swap := child + 1         //判斷子節點是否比根節點大
         if swap != root
             swap(a[root], a[swap])
             root := swap       //根節點降低到子節點
         else
             return

性能:

    最壞的狀況:O(n log n)

    最好的狀況:O(n )

    平均情況:O(n log n)

    不穩定

    額外須要的空間:O(n)

 

java 實現:

public static <T extends Comparable<? super T>> void heapSort(T[] a){
        heapSortHelp(a,a.length);
    }private static <T extends Comparable<? super T>> 
              void heapSortHelp(T[] a, int length) {
        heapify(a,a.length);    //調整爲大根堆的形式
        int end = a.length - 1;        while(end > 0){
            swap(a, 0, end);
            end--;
            siftDown(a,0,end);
        }
    }private static <T extends Comparable<? super T>> void heapify(T[] a, int length) {        int currentSize = length; //存儲根堆的元素個數
        int start = (currentSize - 2) >>> 1;        while (start >= 0) {            
            siftDown(a,start,currentSize - 1);
            start--;
        }
    }private static <T extends Comparable<? super T>> 
              void siftDown(T[] a, int start, int end) {        int root = start;        while (2*root + 1 <= end) {            
            int child = 2*root + 1;            int exchange = root;            if (a[exchange].compareTo(a[child]) < 0) {
                exchange = child;
            }            if ((child + 1 <= end) && (a[child].compareTo(a[child + 1]) < 0)) {
                exchange = child + 1;
            }            if (exchange != root) {
                swap(a, exchange, root);
                root = exchange;
            }else{                return;
            }
        }
    }


7、快速排序

    快速排序(Quicksort)是對冒泡排序的一種改進。由C. A. R. Hoare在1962年提出。它的基本思想是:經過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的全部數據都比另一部分的全部數據都要小,而後再按此方法對這兩部分數據分別進行快速排序,整個排序過程能夠遞歸進行,以此達到整個數據變成有序序列。

僞代碼:

function quicksort(array, left, right)     // 子序列有兩個或多個元素
     if left < right
         選取基準元素,索引pivotIndex //left ≤ pivotIndex ≤ right
         // 肯定基準元素的最終存放位置
         pivotNewIndex := partition(array, left, right, pivotIndex)         // 遞歸快速排序
         quicksort(array, left, pivotNewIndex - 1)
         quicksort(array, pivotNewIndex + 1, right)

function partition(array, left, right, pivotIndex)
     pivotValue := array[pivotIndex]
     swap array[pivotIndex] and array[right]  // 將基準元素移到最後
     storeIndex := left     for i from left to right - 1  // left ≤ i < right
         if array[i] < pivotValue
             swap array[i] and array[storeIndex]
             storeIndex := storeIndex + 1
     swap array[storeIndex] and array[right]  //將基準元素存到其最終存放位置
     return storeIndex

性能:

    最壞的狀況:O(n2)

    最好的狀況:O(n log n)

    平均情況:O(n log n)

    不穩定

    額外須要的空間:O(n)

java 實現:

public static <T extends Comparable<? super T>> void quickSort(T[] a) {
        quickSortHelp(a, 0, a.length - 1);
    }//left 數組最左邊的元素索引,right 數組最右邊的元素索引(包含)private static <T extends Comparable<? super T>> 
             void quickSortHelp(T[] a, int left, int right) {        if (left < right) {            int privotIndex = (left + right) >>> 1;            int privotNewIndex = partition(a, left, right, privotIndex);            //遞歸快速排序(分而治之)
            quickSortHelp(a, left, privotNewIndex - 1);
            quickSortHelp(a, privotNewIndex + 1, right);
        }
    }private static <T extends Comparable<? super T>> 
    int partition(T[] a, int left, int right, int privotIndex) {
        T privotValue = a[privotIndex];
        swap(a, privotIndex, right);        int storeIndex = left;        for (int i = left; i < right; i++) {            if (a[i].compareTo(privotValue) < 0) {
                swap(a, i, storeIndex);
                storeIndex++;
            }
        }
        swap(a, storeIndex, right);        return storeIndex;
    }

8、其餘

    這裏只是給出了java 通配符的應用實例,並不說明java 排序算法就必定要向上面那要來實現(不過若是使用通配符來實現,會是方法的健壯性更強。

相關文章
相關標籤/搜索