【演算法】Java實現七種常用排序演算法

widiot1發表於2018-04-23

分類


  • 插入排序
    • 直接插入排序
    • 希爾排序
  • 交換排序
    • 氣泡排序
    • 快速排序
  • 選擇排序
    • 直接選擇排序
    • 堆排序
  • 歸併排序
    • 歸併
    • 歸併排序

插入排序


直接插入排序

將待排序陣列看作是左右兩部分,左邊為無序區,右邊為有序區。排序過程就是將右邊無序區中的元素逐個插入到左邊有序區中,最後整個陣列為有序區。

package test;

import java.util.Arrays;

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.directInsert(array);
        System.out.println(Arrays.toString(array));
    }

    public static void directInsert(int[] array) {
        int length = array.length;
        int i; //當前要排序的元素,初始為第二個元素,預設第一個元素為有序區
        int j; //有序區中要比較的元素,比較大小後移動或插入
        int temp; //儲存當前要排序的元素,從而空出一個位置用於移動有序區,再將該元素插入有序區的空位
        for (i = 1; i < length; i++) {
            temp = array[i];
            j = i - 1; //空位左邊的第一個元素

            // 降序是找到比他大的元素,升序是找到比他小的元素
            while (j >= 0 && array[j] > temp) {
                array[j + 1] = array[j]; //如果該元素比他大,則將該元素後移,即升序
                j--;
            }
            array[j + 1] = temp; //j+1就是空位
        }
    }
}

希爾排序

將待排序陣列劃分為若干組,在每組內進行直接插入排序,以使整個序列基本有序,然後再對整個序列進行直接插入排序

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.shell(array);
        System.out.println(Arrays.toString(array));
    }

    public static void shell(int[] array) {
        int length = array.length;
        int i; //本組中要排序的元素
        int j; //本組中空位的前一個元素
        int temp; //儲存本組要排序的元素,從而空出一個位置用於移動本組的元素,再將該元素插入本組的空位
        int step; //將陣列分為step組,step為相同組的元素的間隔步長

        // 初始分組,最終分為一組
        step = length / 2;

        //step最終為1
        while (step != 0) {
            //對每組進行直接插入排序,i初始化為每組的第二個元素
            for (i = step; i < length; i++) {
                temp = array[i]; //留出空位用於移動有序區
                j = i - step; //j為本組中空位的前一個元素
                while (j >= 0 && array[j] > temp) {
                    array[j + step] = array[j]; //將大於temp的元素後移,即升序
                    j -= step; //向本組的有序區左邊移動,j為空位前一個元素
                }
                array[j + step] = temp; //j+step為空位
            }

            //進行再次分組
            step /= 2;
        }
    }
}

交換排序


氣泡排序

從一端開始,逐個比較相鄰的兩個元素,發現倒序即交換

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.bubble(array);
        System.out.println(Arrays.toString(array));
    }

    public static void bubble(int[] array) {
        int length = array.length;
        int i; //泡的位置,即迭代次數,一共要冒length-1個泡,最後一個不用冒
        int j; //指向當前正在排序的元素,一直指到上一個泡的下面
        int temp; //用於交換位置時騰出空位

        //泡依次冒到右邊,即每次都是從無序區選一個最大值冒泡
        for (i = (length - 1); i > 0; i--) {
            for (j = 0; j < i; j++) {
                if (array[j] > array[j + 1]) {
                    temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
        }
    }
}

快速排序

首先選定一個元素作為中間元素,然後將陣列中所有元素與該中間元素比較,將比中間元素小的放在陣列前面,比中間元素大的放在陣列後面,再以中間元素作為分界點,得到左右兩部分陣列,而中間元素位於正確位置上,不用參與後續排序。

然後再對左右兩部分分別進行快速排序,即對得到的兩個子陣列再採用相同的方式來排序和劃分,直到每個子陣列僅有一個元素或為空陣列為止,此時陣列所有元素都有序。

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.quick(array, 0, array.length - 1);
        System.out.println(Arrays.toString(array));
    }

    public static void quick(int[] array, int start, int end) {
        int i; //基準左邊的指標,指向正在排序的元素,也指向空位
        int j; //基準右邊的指標,指向正在排序的元素,也指向空位
        int temp; //用於儲存基準,一般是第一個元素,最後將基準放在中間

        if (start < end) {
            i = start;
            j = end;
            temp = array[i];

            while (i < j) {
                //由於以第一位為基準,空位在左邊,則先從右邊找到小於基準的元素,放在左邊
                while (i < j && array[j] > temp) {
                    j--;
                }
                if (i < j) {
                    array[i] = array[j]; //現在j是空位
                    i++;
                }

                //從左邊找到大於基準的元素,然後放在右邊的空位
                while (i < j && array[i] < temp) {
                    i++;
                }
                if (i < j) {
                    array[j] = array[i]; //現在i是空位
                    j--;
                }
            }

            //將基準放在空位
            array[i] = temp;

            //劃分陣列進行遞迴排序,基準不用進行排序
            quick(array, start, i - 1);
            quick(array, i + 1, end);
        }
    }
}

選擇排序


直接選擇排序

在每一趟排序中,在待排序陣列中選出最小或最大的元素放在其最終的位置上

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.select(array);
        System.out.println(Arrays.toString(array));
    }

    public static void select(int[] array) {
        int length = array.length;
        int i; //將要放置正確元素的位置,一共有length-1個,最後一個是正確的
        int j; //指向正在排序的元素
        int min; //初始化最小值,用於和後面元素比較,找到正確值進行交換位置
        int temp; //交換位置時使用

        for (i = 0; i < length - 1; i++) {
            min = i;
            for (j = i + 1; j < length; j++) {
                if (array[min] > array[j]) {
                    min = j; //當前最小值
                }
            }

            //如果最小值不等於最初值,則將換位置
            if (min != i) {
                temp = array[i];
                array[i] = array[min];
                array[min] = temp;
            }
        }
    }
}

堆排序

堆排序的原理比之前的排序方法更復雜,這裡就不多說了,已經有很多資料

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.heap(array);
        System.out.println(Arrays.toString(array));
    }

    public static void heap(int[] array) {
        int length = array.length;
        int temp;
        // 建立初始堆
        for (int i = (length - 1) / 2; i >= 0; i--) {
            sift(array, i, length - 1);
        }
        System.out.println(Arrays.toString(array));
        // 逐步將根結點與末尾元素交換,並調整剩餘陣列為堆,即每次將最大值放在右邊
        for (int i = length - 1; i > 0; i--) {
            temp = array[0];
            array[0] = array[i];
            array[i] = temp;
            sift(array, 0, i - 1);
            System.out.println(Arrays.toString(array));
        }
    }

    // 調整陣列中以k為根的子樹序列為堆,最大下標為m
    // 假定左右子樹都是堆
    private static void sift(int[] array, int k, int m) {
        int i = k; // i表示當前根結點
        int j = 2 * i + 1; // j指向當前根結點的左孩子
        int temp;
        // 保證i不是葉子
        while (j <= m) {
            // 讓j指向左右孩子的最大者
            if (j < m && array[j] < array[j + 1]) {
                j += 1;
            }
            // 如果父結點最大,則建堆結束
            if (array[i] >= array[j]) {
                break;
            } else {
                temp = array[i];
                array[i] = array[j]; // 大的孩子結點值上移
                array[j] = temp; // 父結點下沉
                i = j; // i表示新的根結點
                j = 2 * i + 1; // j變為當前根結點的左孩子
            }
        }
    }
}

歸併排序


歸併

將多個有序表合併成一個有序表

public class Sort {
    public static void main(String[] args) {
        int[] A = {0,1,2,3,4,5};
        int[] B = {2,4,6,8,10,11};
        array = Sort.merge(A, B);
        System.out.println(Arrays.toString(array));
    }

    public static int[] merge(int[] A, int[] B) {
        int aLength = A.length;
        int bLength = B.length;
        int[] C = new int[aLength + bLength];
        int a = 0, b = 0, c = 0;
        // 先按最短長度合併
        while (a < aLength && b < bLength) {
            if (A[a] > B[b]) {
                C[c++] = B[b++];
            } else {
                C[c++] = A[a++];
            }
        }
        // 填入剩餘元素
        while (a < aLength) {
            C[c++] = A[a++];
        }
        while (b < bLength) {
            C[c++] = B[b++];
        }
        return C;
    }
}

歸併排序

將整個表看成n個有序子表,然後兩兩歸併

public class Sort {
    public static void main(String[] args) {
        int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
        Sort.mergeSort(array, 0, array.length - 1);
        System.out.println(Arrays.toString(array));
    }

    public static void mergeSort(int[] array, int low, int high) {
        int mid = (low + high) / 2;
        if (low < high) {
            mergeSort(array, low, mid);
            mergeSort(array, mid + 1, high);
            merge(array, low, mid, high);
        }
    }

    public static void merge(int[] array, 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 (array[i] < array[j]) {
                temp[k++] = array[i++];
            } else {
                temp[k++] = array[j++];
            }
        }
        // 填入剩餘元素
        while (i <= mid) {
            temp[k++] = array[i++];
        }
        while (j <= high) {
            temp[k++] = array[j++];
        }
        // 修改原陣列
        for (int m = 0; m < temp.length; m++) {
            array[low + m] = temp[m];
        }
    }
}

相關文章