演算法-排序演算法思想及實現

glmapper發表於2017-11-28

排序演算法主要有:插入排序,選擇排序,氣泡排序,希爾排序,歸併排序,快速排序,堆排序。這裡的排序指的是內部排序,也就是基於記憶體的排序,基於記憶體的排序是基於大O模型的,可以使用大O模型來衡量演算法的效能
摘自我自己的部落格園:www.cnblogs.com/myadmin/p/5… 中的部分排序演算法。

插入排序

基本思想:每一步都將一個待排資料按其大小插入到已經排序的資料中的適當位置,直到全部插入完畢。

原始:4 3 1 2
1)    3 4 1 2
2)    1 3 4 2
3)    1 2 3 4複製程式碼

核心程式碼:

/**
     * 插入排序
     */
    public static int[] insertSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int index = i;// index當前掃描到的元素下標
            int temp = arr[i];
            // 尋找插入的位置
            while (index > 0 && temp < arr[index - 1]) {
                arr[index] = arr[index - 1];
                index--;
            }
            arr[index] = temp;
        }
        return arr;
    }複製程式碼

選擇排序

基本思想:從所有序列中先找到最小的,然後放到第一個位置。之後再看剩餘元素中最小的,放到第二個位置……以此類推,就可以完成整個的排序工作了。可以很清楚的發現,選擇排序是固定位置,找元素。相比於插入排序的固定元素找位置,是兩種思維方式。

3 2 1 4 6 5

初始化索引位置為0 
尋找最小值所在位置交換:1 2 3 4 6 5

初始化索引位置為1
尋找最小值所在位置交換:1 2 3 4 6 5

依次類推!複製程式碼

核心程式碼:

/**
     * 選擇排序
     */
    public static int[] selectSort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            int minVal = arr[i];
            int index = i;
            for (int j = i + 1; j < arr.length; j++) {// 找到最小元素
                if (arr[j] < minVal) {
                    minVal = arr[j];
                    index = j;
                }
            }
            arr[index] = arr[i];
            arr[i] = minVal;
        }
        return arr;
    }複製程式碼

氣泡排序

基本思想:原理是臨近的數字兩兩進行比較,按照從小到大或者從大到小的順序進行交換。
核心程式碼:

/**
     * 氣泡排序
     * 
     * @param arr
     *            輸入的待排陣列
     * @return 返回排序號的陣列
     */
    public static int[] bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            for (int j = 1; j < arr.length; j++) {
                if (arr[j - 1] > arr[j]) {
                    int temp = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        return arr;
    }複製程式碼

希爾排序

基本思想:先取一個小於n的整數d1作為第一個增量,把檔案的全部記錄分組。所有距離為d1的倍數的記錄放在同一個組中。先在各組內進行直接插入排序;然後,取第二個增量d2<d1重複上述的分組和排序,直至所取的增量 =1( < …<d2<d1),即所有記錄放在同一組中進行直接插入排序為止。(下圖來自百度圖片)

核心程式碼:

/**
 * 希爾排序
 * 
 * @author sgl
 * 
 */
public class ShellSort {

    public static int[] shellSort(int[] arr) {
        int step = arr.length / 2;// 初始步長

        while (1 <= step) {
            for (int i = step; i < arr.length; i++) {
                if (arr[i] < arr[i - step]) {
                    int temp = arr[i];
                    arr[i] = arr[i - step];
                    arr[i - step] = temp;
                }
            }
            step = step / 2;
            for (int i = 0; i < arr.length; i++) {
                System.out.print(arr[i]+",");
            }
            System.out.println();
        }

        return arr;
    }複製程式碼

歸併排序

基本思想:將待排序序列R[0...n-1]看成是n個長度為1的有序序列,將相鄰的有序表成對歸併,得到n/2個長度為2的有序表;將這些有序序列再次歸併,得到n/4個長度為4的有序序列;如此反覆進行下去,最後得到一個長度為n的有序序列。
歸併排序其實要做兩件事:
(1)“分解”——將序列每次折半劃分。
(2)“合併”——將劃分後的序列段兩兩合併後排序。

核心程式碼:

public static int[] sort(int[] nums, int low, int high) {
        int mid = (low + high) / 2;
        if (low < high) {
            sort(nums, low, mid);// 左邊
            sort(nums, mid + 1, high);// 右邊
            merge(nums, low, mid, high);// 左右歸併
        }
        return nums;
    }
    public static void merge(int[] nums, int low, int mid, int high)           {
        int[] temp = new int[high - low + 1];
        int i = low;// 左指標
        int j = mid + 1;// 右指標
        int k = 0;
        // 把較小的數先移到新陣列中
        while (i <= mid && j <= high) {
            if (nums[i] < nums[j]) {
                temp[k++] = nums[i++];
            } else {
                temp[k++] = nums[j++];
            }
        }
        // 把左邊剩餘的數移入陣列
        while (i <= mid) {
            temp[k++] = nums[i++];
        }
        // 把右邊邊剩餘的數移入陣列
        while (j <= high) {
            temp[k++] = nums[j++];
        }
        // 把新陣列中的數覆蓋nums陣列
        for (int k2 = 0; k2 < temp.length; k2++) {
            nums[k2 + low] = temp[k2];
        }
    }

}複製程式碼

快速排序

基本思想:快速排序採用的思想是分治思想。
快速排序是找出一個元素(理論上可以隨便找一個)作為基準,然後對陣列進行分割槽操作,使基準左邊元素的值都不大於基準值,基準右邊的元素值 都不小於基準值,如此作為基準的元素調整到排序後的正確位置。遞迴快速排序,將其他n-1個元素也調整到排序後的正確位置。最後每個元素都是在排序後的正 確位置,排序完成。所以快速排序演算法的核心演算法是分割槽操作,即如何調整基準的位置以及調整返回基準的最終位置以便分治遞迴。

核心程式碼:

/**
 * 快速排序
 * 
 * @author sgl
 * 
 */
public class QuickSort {
    static void quicksort(int n[], int left, int right) {
        int dp;
        if (left < right) {
            dp = partition(n, left, right);
            quicksort(n, left, dp - 1);
            quicksort(n, dp + 1, right);
        }
    }

    static int partition(int n[], int left, int right) {
        int pivot = n[left];
        while (left < right) {
            while (left < right && n[right] >= pivot)
                right--;
            if (left < right)
                n[left++] = n[right];
            while (left < right && n[left] <= pivot)
                left++;
            if (left < right)
                n[right--] = n[left];
        }
        n[left] = pivot;
        return left;
    }

}複製程式碼

相關文章