常見排序算法總結與實現(冒泡、插入、選擇、希爾、堆排序、歸併、快排)

常見排序算法總結與實現(冒泡、插入、選擇、希爾、堆排序、歸併、快排)

本文使用Java實現這幾種排序算法。
如下是對排序算法整體的介紹。html

冒泡排序

  1. 比較相鄰的元素。若是第一個比第二個大,就交換他們兩個。
  2. 對每一對相鄰元素做一樣的工做,從開始第一對到結尾的最後一對。這步作完後,最後的元素會是最大的數。
  3. 針對全部的元素重複以上的步驟,除了最後一個。
  4. 持續每次對愈來愈少的元素重複上面的步驟,直到沒有任何一對數字須要比較。

時間複雜度:O(n^2),最優時間複雜度:O(n),平均時間複雜度:O(n^2)算法

 

public static void bubbleSort(Comparable[] a) {
    int j, flag;
    Comparable temp;
    for (int i = 0; i < a.length; i++) {
        flag = 0;
        for (j = 1; j < a.length - i; j++) {
            if (a[j].compareTo(a[j - 1]) < 0) {
                temp = a[j];
                a[j] = a[j - 1];
                a[j - 1] = temp;
                flag = 1;
            }
        }
        // 若是沒有交換,表明已經排序完畢,直接返回
        if (flag == 0) {
            return;
        }
    }
}

 

插入排序

  1. 從第一個元素開始,該元素能夠認爲已經被排序
  2. 取出下一個元素,在已經排序的元素序列中從後向前掃描
  3. 若是該元素(已排序)大於新元素,將該元素移到下一位置
  4. 重複步驟3,直到找到已排序的元素小於或者等於新元素的位置
  5. 將新元素插入到該位置後
  6. 重複步驟2~5

時間複雜度:O(n^2),最優時間複雜度:O(n),平均時間複雜度:O(n^2)shell

下面展現了兩種插入排序的實現,第二種方法減小了交換次數。性能

 

public static void insertionSort(Comparable[] a) {
    int length = a.length;
    Comparable temp;
    for (int i = 1; i < length; i++) {
        for (int j = i; j > 0 && a[j].compareTo(a[j - 1]) < 0; j--) {
            temp = a[j];
            a[j] = a[j - 1];
            a[j - 1] = temp;
        }
    }
}

 

// 對實現Comparable的類型進行排序,先將大的元素都向右移動,減小一半交換次數

 

public static void insertionSort(Comparable[] a) {
    int length = a.length;
    Comparable temp;
    int j;
    for (int i = 1; i < length; i++) {
        temp = a[i];
        for (j = i; j > 0 && temp.compareTo(a[j - 1]) < 0; j--) {
            a[j] = a[j - 1];
        }
        a[j] = temp;
    }
}

 

選擇排序

首先在未排序序列中找到最小元素,存放到排序序列的起始位置,而後,再從剩餘未排序元素中繼續尋找最小元素,而後放到已排序序列的末尾。優化

時間複雜度:O(n^2),最優時間複雜度:O(n^2),平均時間複雜度:O(n^2)ui

 

public static void selectionSort1(Comparable[] a) {
    int length = a.length;
    int min;
    Comparable temp;
    for (int i = 0; i < length; i++) {
        min = i;
        for (int j = i + 1; j < length; j++) {
            if (a[j].compareTo(a[min]) < 0) {
                min = j;
            }
        }
        temp = a[min];
        a[min] = a[i];
        a[i] = temp;
    }
}

 

希爾排序

希爾排序經過將比較的所有元素分爲幾個區域來提高插入排序的性能。這樣可讓一個元素能夠一次性地朝最終位置前進一大步。而後算法再取愈來愈小的步長進行排序,算法的最後一步就是普通的插入排序,可是到了這步,需排序的數據幾乎是已排好的了(此時插入排序較快)。spa

時間複雜度:根據步長而不一樣,最優時間複雜度:O(n),平均時間複雜度:根據步長而不一樣code

 

public static void shellSort(Comparable[] a) {
    int length = a.length;
    int h = 1;
    Comparable temp;
    while (h < length / 3) {
        h = 3 * h + 1;
    }
    while (h >= 1) {
        for (int i = h; i < length; i++) {
            for (int j = i; j >= h && a[j].compareTo(a[j - h]) < 0; j -= h) {
                temp = a[j];
                a[j] = a[j - h];
                a[j - h] = temp;
            }
        }
        h /= 3;
    }
}

 

堆排序

  1. 建立最大堆(Build_Max_Heap):將堆全部數據從新排序
  2. 堆排序(HeapSort):移除位在第一個數據的根節點,並作最大堆調整的遞歸運算

時間複雜度:O(nlogn),最優時間複雜度:O(nlogn),平均時間複雜度:O(nlogn)htm

 

public static void heapSort(Comparable[] a) {
    int length = a.length;
    Comparable temp;
    for (int k = length / 2; k >= 1; k--) {
        sink(a, k, length);
    }
    while (length > 0) {
        temp = a[0];
        a[0] = a[length - 1];
        a[length - 1] = temp;
        length--;
        sink(a, 1, length);
    }
}

private static void sink(Comparable[] a, int k, int n) {
    Comparable temp;
    while (2 * k <= n) {
        int j = 2 * k;
        if (j < n && a[j - 1].compareTo(a[j]) < 0) {
            j++;
        }
        if (a[k - 1].compareTo(a[j - 1]) >= 0) {
            break;
        }
        temp = a[k - 1];
        a[k - 1] = a[j - 1];
        a[j - 1] = temp;
        k = j;
    }
}

 

歸併排序

歸併操做(merge),也叫歸併算法,指的是將兩個已經排序的序列合併成一個序列的操做。歸併排序算法依賴歸併操做。blog

時間複雜度:O(nlogn),最優時間複雜度:O(n),平均時間複雜度:O(nlogn),空間複雜度O(n)

自頂向下的歸併排序

 

private static Comparable[] aux;
// 自頂向下
public static void mergeSort(Comparable[] a) {
    aux = new Comparable[a.length];
    mergeSort(a, 0, a.length - 1);
}

public static void mergeSort(Comparable[] a, int lo, int hi) {
    if (hi <= lo) {
        return;
    }
    int mid = (lo + hi) >>> 1;
    mergeSort(a, lo, mid);
    mergeSort(a, mid + 1, hi);
    merge(a, lo, mid, hi);
}

public static void merge(Comparable[] a, int lo, int mid, int hi) {
    int i = lo, j = mid + 1;

    for (int k = lo; k <= hi; k++) {
        aux[k] = a[k];
    }

    for (int k = lo; k <= hi; k++) {
        if (i > mid) {
            a[k] = aux[j++];
        } else if (j > hi) {
            a[k] = aux[i++];
        } else if (aux[j].compareTo(aux[i]) < 0) {
            a[k] = aux[j++];
        } else {
            a[k] = aux[i++];
        }
    }
}

 

自底向上的歸併排序

 

private static Comparable[] aux;

// 自底向上
public static void mergeSort(Comparable[] a) {
    int length = a.length;
    aux = new Comparable[length];
    for (int sz = 1; sz < length; sz = sz + sz) {
        for (int lo = 0; lo < length - sz; lo += sz + sz) {
            merge(a, lo, lo + sz - 1, Math.min(lo + sz + sz - 1, length - 1));
        }
    }
}

public static void merge(Comparable[] a, int lo, int mid, int hi) {
    int i = lo, j = mid + 1;

    for (int k = lo; k <= hi; k++) {
        aux[k] = a[k];
    }

    for (int k = lo; k <= hi; k++) {
        if (i > mid) {
            a[k] = aux[j++];
        } else if (j > hi) {
            a[k] = aux[i++];
        } else if (aux[j].compareTo(aux[i]) < 0) {
            a[k] = aux[j++];
        } else {
            a[k] = aux[i++];
        }
    }
}

 

快速排序

  1. 從數列中挑出一個元素,稱爲"基準"(pivot),
  2. 從新排序數列,全部元素比基準值小的擺放在基準前面,全部元素比基準值大的擺在基準的後面(相同的數能夠到任一邊)。在這個分區結束以後,該基準就處於數列的中間位置。這個稱爲分區(partition)操做。
  3. 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。

時間複雜度:O(n^2),最優時間複雜度:O(nlogn),平均時間複雜度:O(nlogn)

快排的時間複雜度跟選取基準的方法有關,一下是默認選擇了第一個元素做爲基準,隨機性較大。
能夠在序列中選取開始中間結尾三個數的中位數做爲基準,進行優化。

 

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

public static void quickSort(Comparable[] a, int lo, int hi) {
    if (hi <= lo) {
        return;
    }
    int j = partition(a, lo, hi);
    quickSort(a, lo, j - 1);
    quickSort(a, j + 1, hi);
}

public static int partition(Comparable[] a, int lo, int hi) {
    int i = lo, j = hi + 1;
    Comparable temp;
    Comparable v = a[lo];
    while (true) {
        while (a[++i].compareTo(v) < 0) {
            if (i == hi) {
                break;
            }
        }
        while (v.compareTo(a[--j]) < 0) {
            if (j == lo) {
                break;
            }
        }
        if (i >= j) {
            break;
        }
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
    temp = a[lo];
    a[lo] = a[j];
    a[j] = temp;
    return j;
}
相關文章
相關標籤/搜索