sort

package com.light.algorithm {
    /**
     * 排序算法合集·
     * @author light
     */
    public class Sort {
        
        private static var len:uint = 0;
        
         /**
         * 冒泡排序 Bubble Sort 
         * 原理:
         * 比較n輪,每一輪都把最大元素移動到數組後端。
         * @return
         */
        public static function bubbleSort(arr:Array):Array {
            len = arr.length;
            for (var i:int = 0; i < len; i++) {
                for (var j:int = i + 1; j < len; j++) {
                    if (arr[i] > arr[j]) {
                        swap(arr, i, j);
                    }
                }
            }
            return arr;
        }
        
         /**
         * 插入排序 Insert Sort
         * 從第二個元素開始,由於左側的數組爲排序後的數組,
         * 只要將當前元素插入到左側數組的適當位置,就能保持數組爲有序
         * 保證左邊的是有序的 
         * 而後處理第三個元素...直到最後一個元素
         * @return
         */
        public static function insertSort(arr:Array):Array {
            len = arr.length;
            for (var i:int = 1; i < len; i++) {
                for (var j:int = i; j > 0 && arr[j] < arr[j - 1]; j--) {
                    swap(arr, j, j -1);
                }
            }
            return arr;
        }
        
        /**
         * 折半搜索插入排序 BinarySearchThenInsert Sort
         * 原理與插入排序相似,不一樣點在於尋找插入位置的時候,採起的是折半查找方法
         * @return
         */
        public static function binsertSort(arr:Array):Array {
            len = arr.length;
            for (var i:int = 1; i < len; i++) { 
                if (arr[i] < arr[0]) { 
                    var temp:int = arr[i];
                    for (var j:int = i - 1; j >= 0; j--) { 
                        arr[j + 1] = arr[j];
                    }
                    arr[0] = temp;
                } else if (arr[i] < arr[i - 1]) { 
                    var larrange:int = 0;
                    var rarrange:int = i - 1;
                    while (rarrange - larrange > 1) {
                        var p:int = (rarrange + larrange + 1) / 2;
                        if (arr[i] < arr[p]) { 
                            rarrange = p;
                        } else {
                            larrange = p;
                        }
                    }
                    temp = arr[i];
                    for (j = i - 1; j >= larrange + 1; j--) { 
                        arr[j + 1] = arr[j];
                    }
                    arr[larrange + 1] = temp;
                }
            }
            return arr;
        }
        
        /* 堆排序 Heap Sort
         * 利用了堆的易調整的特色來進行的一種選擇排序。
         * 以大頂堆爲例,什麼是大頂堆?
         * 大頂堆的邏輯結構是一顆徹底二叉樹,[把滿二叉樹最後一層右側的一些葉子摘掉]
         * 假設其高度爲h,則元素個數介於
         * 1 + 2 + ... + exp(2, h - 2) ~ 1 + 2 + ... + exp(2, h -1)之間
         * 符合以下定義爲大頂堆:(此定義基於大頂堆的順序存儲結構)
         * for (int i = arr.length - 1; i > 0; i--) {
         *         任意 arr[i] <= arr[(i - 1)/2];
         * }
         * (還有一種是小頂堆,不一樣的只是比較時候的大於號方向不一樣)。
         * 容易想到,當堆頂元素(MaxValue)被替換後,
         * 至多隻要在雙親和子節點間進行h(大頂堆的高度) - 1次交換,
         * (參照交換算法能夠發現比較次數通常來講是交換次數的2~3倍,也不算多)
         * 就能夠造成新的大頂堆。由此大大提升了排序效率。
         * @return
         */
        public static function heapSort(arr:Array):Array {
            // 初始化無序數組爲大頂堆
            for (var i:int = arr.length - 2; i >= 0; i--) {
                adjustHeap(arr, i, arr.length - 1);
            }
            // 將最大值元素交換至數組末端,並調整前端爲大頂堆,循環直至前端只剩下一個元素
            for (i = arr.length - 1; i > 0; i--) {
                swap(arr, 0, i);
                adjustHeap(arr, 0, i - 1);
            }
            return arr;
        }
        
        /**
         * 將除頂(不肯定是否知足大頂堆條件)外,左子樹和右子樹都爲一個堆的數組調整爲大頂堆
         * @param arr 待調整數組
         * @param from 頂的指針
         * @param to    調整的末端(就是調整array[from]...arr[to]這一段爲一個大頂堆)
         */
        private static function adjustHeap(arr:Array, from:int, to:int):void {
            var i:int = 0;
            // 比較節省比較次數的方法,只要比較到比其左右子樹的根結點的值都大,就能夠return了
            while (from + 2 * i + 2 <= to) {
                if (arr[from + i] < arr[from + 2 * i + 1]
                     || arr[from + i] < arr[from + 2 * i + 2]) {
                    if (arr[from + 2 * i + 1] > arr[from + 2 * i + 2]) {
                        swap(arr, from + i, from + 2 * i + 1);
                        i += i + 1;
                    } else {
                        swap(arr, from + i, from + 2 * i + 2);
                        i += i + 2;
                    }
                } else {
                    return;
                }
            }
            if (from + 2 * i + 1 == to
                    && arr[from + i] < arr[from + 2 * i + 1]) {
                // 有時會出現僅存在左子樹的狀況(左子樹爲調整數組的最後一個元素)
                swap(arr, from + i, from + 2 * i + 1);
            }
        }
        
        /**
         * 快速排序 Quick Sort
         * 選擇數組中的一個元素做爲標準,將全部比標準小的元素放到左邊,
         * 全部比標準大的元素放到右邊。
         * 並對左邊和右邊的元素作同樣的快速排序過程。
         * @return
         */
        public static function quickSort(arr:Array):Array {
              quick(arr, 0, arr.length - 1);
              return arr;
        }

        /**
         * 選擇數組中的一個元素做爲標準,將全部比標準小的元素放到左邊,
         * 全部比標準大的元素放到右邊。
         * 並對左邊和右邊的元素作同樣的快速排序過程。
         * @param arr
         * @param startIndex
         * @param endIndex
         */
        private static function quick(arr:Array, startIndex:int, endIndex:int):void {
            var pIndex:int = startIndex;
            for (var i:int = startIndex + 1; i <= endIndex; i++) {
                if (arr[i] < arr[pIndex]) {
                    var temp:int = arr[i];
                    for (var j:int = i; j > pIndex; j--) {
                        arr[j] = arr[j - 1];
                    }
                    arr[pIndex] = temp;
                    pIndex++;
                }

            }
            if (pIndex - startIndex > 1) {
                quick(arr, startIndex, pIndex - 1);
            }
            if (endIndex - pIndex > 1) {
                quick(arr, pIndex + 1, endIndex);
            }
        }
        
        /**
         * 希爾排序 Shell Sort
         * <p>原理:
         * 分別以數組大小的1/2,1/4,1/8....1的做爲步伐d,
         * 將array[i],arr[i + d],arr[i + 2d]....arr[i + nd]看做一個數組進行排序,
         * 與插入排序相比,由於能夠更有效的消除逆序,所以交換次數是不多的,
         * 缺點是比較次數過多
         * @return
         */
        public static function shellSort(arr:Array):Array {
            len = arr.length
            for (var d:int = len / 2; d > 0; d = d / 2) { 
                for (var i:int = d; i < len; i++) { 
                    for (var j:int = i; j >= d; j = j - d) { 
                        if (arr[j] < arr[j - d]) { 
                            swap(arr, j, j - d);
                        }
                    }
                }
            }
            return arr;
        }
        
        /**
         * 簡單選擇排序 SimpleSelection Sort
         * <p>原理:每遍歷未排序部分一次都選出一個最小值,並將最小值元素移動到數組前端
         * @return
         */
        public static function simpleSelectionSort(arr:Array):Array {
            // 重複此過程:選取最小值,並將其交換至數組前端
            var minIndex:int = 0;
            for (var i:int = 0; i < arr.length; i++) {
                minIndex = i;
                for (var j:int = i + 1; j < arr.length; j++) {
                    if (arr[j] < arr[minIndex]) {
                        minIndex = j;
                    }
                }
                swap(arr, minIndex, i);
            }
            return arr;
        }
        
        /**
         * 歸併排序 Merge Sort
         * <p>原理:
         * 分治。將數組分爲左,右兩部分,
         * 首先將數組分爲左右兩部分,分別進行歸併排序,
         * 而後合併左右兩部分的排序結果就構成了一個有序數組。
         * @return
         */
        public static function mergeSort(arr:Array):Array {
            mergeR(arr, 0, arr.length - 1);
            return arr;
        }

        /**
         * 遞歸對數組進行歸併排序
         * @param arr
         * @param startIndex
         * @param endIndex
         */
        private static function mergeR(arr:Array, startIndex:int, endIndex:int):void {
            if (startIndex < endIndex) {
                var mid:int = (startIndex + endIndex) / 2;
                // 對包括中點在內的左側數組區間進行歸併排序
                mergeR(arr, startIndex, mid);
                // 對中點以後的右側數組區間進行歸併排序
                mergeR(arr, mid + 1, endIndex);
                // 合併左和右兩個獨立的有序區間爲一個有序區間
                merge(arr, startIndex, mid, endIndex);
            }
        }

       /**
         * 將array數組的兩個有序區間array[startIndex]...arr[midIndex]
         * 和array[midIndex + 1]...arr[endIndex]合併爲一個有序區間
         * arr[startIndex]...arr[endIndex]
         * @param arr
         * @param startIndex
         * @param midIndex
         * @param endIndex
         */
        private static function merge(arr:Array, startIndex:int, midIndex:int, endIndex:int):void {
            var arrTemp:Array = new Array(endIndex - startIndex + 1);            
            var pr:int = 0;
            var p1:int = startIndex;
            var p2:int = midIndex + 1;
            while (p1 <= midIndex || p2 <= endIndex) {
                if (p1 == midIndex + 1) {
                    while (p2 <= endIndex) {
                        arrTemp[pr++] = arr[p2++];
                    }
                } else if (p2 == endIndex + 1) {
                    while (p1 <= midIndex) {
                        arrTemp[pr++] = arr[p1++];
                    }
                } else if (arr[p1] <= arr[p2]) {
                    arrTemp[pr++] = arr[p1++];
                } else {
                    arrTemp[pr++] = arr[p2++];
                }
            }
            for (p1 = startIndex, p2 = 0; p1 <= endIndex; p1++, p2++) {
                arr[p1] = arrTemp[p2];
            }
        }
        
        /**
         * 交換。。。
         * @param    arr
         * @param    i
         * @param    j
         */
        private static function swap(arr:Array, i:int, j:int):void {
            var temp:int = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        
    }

}
相關文章
相關標籤/搜索