基礎算法-歸併排序的理解與實現-Android版

歸併排序:採用分治法排序,先分後治; 將數組分成兩個數列,再將左子數列分成兩個數列,再將右子數列分成兩個數列...直到每一個子數列只有一個數字; 然後就是治,也稱爲merge;將兩個有序數列合併成一個有序數列的過程;

代碼實現與理解-----遞歸實現:

        int a[] = {2, 3, 5, 6, 9, 0, 4, 7, 8};
        // 歸併排序
        sort(a, 0, a.length-1);
        for (int h=0;h < a.length;h ++){
            Log.i("chy1234","==結果數據==="+a[h]);
        }

/******************************************************/
    /**
     * 遞歸進行歸併排序
     *
     * @param a
     * @param left
     * @param right
     */
    private void sort(int []a, int left, int right){
        if (left == right){
            return;
        }
        // 找到數列中間點
        int mid = left + (right  - left)/2;
        // 對於中間點左邊進行排序
        sort(a, left, mid);
        // 對於中間點右邊進行排序
        sort(a, mid +1, right);
        // 排序完成後,合併左右兩個數列
        merge(a,left, mid+1, right);
    }



    /**
     * 將兩個有序的數列合併成爲一個有序的數列
     * @param a    數列
     * @param leftPoint  左起始點
     * @param rightPoint 右起始點
     * @param rightBound 右邊緣
     */
    private void merge(int []a, int  leftPoint, int rightPoint, int rightBound){
        // 找到中間位置
        int mid = rightPoint -1;
        // 初始化數組用來裝臨時數據(長度爲要排序的數列長度)
        int result[] = new int[rightBound - leftPoint +1];
        int i = leftPoint;
        int j = rightPoint;
        int k = 0;
        // 遍歷兩邊的數列,按照順序填入result[]中
        while(i <= mid && j <= rightBound) {
            if (a[i] <= a[j]) {
                result[k ++] = a[i ++];
            } else {
                result[k ++] = a[j ++];

            }
        }
        // 如果左邊數列有剩餘,填入result[]尾部
        while (i <= mid) {
            result[k++] = a[i++];
        }
        // 如果右邊數列有剩餘,填入result[]尾部
        while (j <= rightBound) {
            result[k++] = a[j++];
        }
        // 將排序好的數列result[]重新賦值給初始數列a[]
        for (int h = 0 ; h < result.length; h ++){
            a[leftPoint ++] = result[h];
        }
    }

代碼的理解與實現--非遞歸實現:

        int a[] = {5, 3, 4, 8, 9, 0, 2, 6, 7};
        /**
         * 外層循環定義合併次數
         * 根據合併數組內的元素個數(1,2,4,8.....)得出外合併次數
         * 第1次合併 1  個元素   第2次合併2個元素;
         * 第3次合併 4 個元素 ...
         */
        for (int i = 1; i < a.length; i = i * 2) {
            int left = 0;
            int mid = left + i - 1;
            int right = mid + i;
            while (right < a.length) {
                merge(a, left, mid+1, right);
                left = right + 1;
                mid = left + i - 1;
                right = mid + i;
            }
            if (left < a.length && mid < a.length) {
                merge(a, left, mid+1, a.length - 1);
            }
        }

        for (int h = 0; h < a.length; h++) {
            Log.i("chy1234", "==結果數據===" + a[h]);
        }

/*************merge 方法與遞歸的 merge 保持一致******************/
   /**
     * 將兩個有序的數列合併成爲一個有序的數列
     *
     * @param a          數列
     * @param leftPoint  左起始點
     * @param rightPoint 右起始點
     * @param rightBound 右邊緣
     */
    private void merge(int[] a, int leftPoint, int rightPoint, int rightBound) {
        // 找到中間位置
        int mid = rightPoint - 1;
        // 初始化數組用來裝臨時數據(長度爲要排序的數列長度)
        int result[] = new int[rightBound - leftPoint + 1];
        int i = leftPoint;
        int j = rightPoint;
        int k = 0;
        // 遍歷兩邊的數列,按照順序填入result[]中
        while (i <= mid && j <= rightBound) {
            if (a[i] <= a[j]) {
                result[k++] = a[i++];
            } else {
                result[k++] = a[j++];

            }
        }
        // 如果左邊數列有剩餘,填入result[]尾部
        while (i <= mid) {
            result[k++] = a[i++];
        }
        // 如果右邊數列有剩餘,填入result[]尾部
        while (j <= rightBound) {
            result[k++] = a[j++];
        }
        // 將排序好的數列result[]重新賦值給初始數列a[]
        for (int h = 0; h < result.length; h++) {
            a[leftPoint++] = result[h];
        }
    }

歸併排序的記憶: 遞歸實現,難點在於merge方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章