數據結構與算法之高級排序(希爾/堆)

基礎排序
數據結構與算法之基礎排序(冒泡/插入/選擇)<十>

希爾排序

希爾排序又稱爲縮小增量排序。該算法是一個泛化的插入排序,插入排序在序列幾乎有序的情況下非常有效。希爾排序利用此特性,分多路並使用不同的間距進行插入排序,當間距爲1是則就是簡單的插入排序,本質上希爾排序是插入排序的簡單拓展 

優點
    對中等大小的序列非常有效 
    是所有已知O(n^2)排序算法中最快的 
    相對簡單的排序算法 
缺點 
    較大序列不是個好的選擇
    不及 歸併 堆 快速排序有效 
    明顯比 歸併 堆 快速 排序慢 
算法
    選擇合適的間距 將序列分成n路
    每路使用插入排序
    重複上述過程直至間距爲1

堆排序

堆排序是一種基於比較的排序算法,該算法同時屬於選擇排序。雖然在大多數計算機上的運行效率低於快速排序。但是堆排序最大的優勢是在最壞情況下O(nlogn) 

關於堆的基礎知識參考數據結構與算法之優先隊列<九>

以下算法實現僅供參考若有錯誤歡迎指正

希爾排序

public void sortByShell2(int[] a) {
        int d = SIZE;
        while (true) {
            // 將數組分成d路然後每列進行插入排序
            d = d / 2;
            // 遍歷所有路   每路進行插入排序
            for (int j = d; j < arr.length; j++) {
                // 若第i個元素大於i-1元素,該位置元素位置正確。小於的話,後移空出位置
                if (a[j] < a[j - d]) {
                    //下個元素位置
                    int n = j - d;
                    // 複製爲哨兵,即存儲待排序元素
                    int x = a[j]; 
                    // 先後移 空出位置
                    a[j] = a[j - d]; 
                    // 循環查找插入位置 直至找到或者到頭
                    while (n >= d && x < a[n - d]) { 
                        a[n] = a[n - d];
                        //下個元素位置
                        n = n - d; 

                    }
                    // 插入到正確位置
                    a[n] = x; 
                }
            }
            // 步長爲1時便是插入排序了 排序也就完成了
            if (d == 1) {
                break;
            }
        }
    }

堆排序

    // 調整堆父節點小
    public void adjustHeap(int[] heap, int node, int length) {
        // 保存被調整的節點
        int temp = heap[node];
        // 利用完全二叉樹的特殊性,父節點與子節點的關係child=father*2+1
        int child = node * 2 + 1;
        while (child < length) {
            // 如果存在右孩子且右孩子小於左孩子
            if ((child + 1) < length && heap[child] < heap[child + 1]) {
                // 選擇小的孩子
                ++child;
            }
            // 如果父節點大於孩子中最小的
            if (heap[node] < heap[child]) {
                heap[node] = heap[child];
                // 向下繼續調整
                node = child;
                child = node * 2 + 1;
            } else {
                break;
            }
            // 調整完畢 找到了正確位置
            heap[node] = temp;
        }

    }

    // 建立堆
    public void buildHeap(int[] arr, int length) {
        // 根據child=node*2+1可以算出數列中最後一個節點
        for (int node = (length - 1) / 2; node >= 0; --node) {
            // 從下自上將所有的節點調整一遍
            adjustHeap(arr, node, length);
        }
    }

    // 將創建好的堆進行堆排序
    public void sortByHeap(int[] array, int length) {
        buildHeap(array, length);
        int temp;
        // 將數組遍歷從尾部到頂依次與根節點互換
        for (int i = length - 1; i > 0; --i) {
            temp = array[i];
            array[i] = array[0];
            array[0] = temp;
            // 將根節點替換後從上向下調整
            adjustHeap(array, 0, i);

        }
    }

到此希爾排序和堆排序介紹完畢

下一篇 數據結構與算法之高級排序(快速/歸併)<十二>

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