1. 程式人生 > >算法排序之堆排序

算法排序之堆排序

light sof lock microsoft 大堆 找到 turn 如果 結點

在算法導論第三版中介紹“堆排序是一種原地排序,如果試圖引入數組,那麽將失去這一優勢。”堆排序的基礎是在原有堆上進行排序,即將等待排序的集合先建堆

1.建立最大堆(Max_Heapify)

最大堆滿足條件A[Parent[i]]>=A[i]
最大堆唯一能確立的就是數組中的最大元素,相當於一個復雜的Max方法,但是重新確立一個最大堆比較快

//偽代碼片段
Max_Heapify(A,i) l=LEFT(i) r=RIGHT(i) if l<=A.heap-size and A[l]>A[i] largest=l else largest=i if r<=A.heap-size and A[r]>A[largest] largest=r if largest !=i exchange A[i] with A[largest] Max_Heapify(A,largest)

 

2.堆排序(Heap_Sort)

每次從最大堆中選出第一個元素Array[0](數組中最大的元素),將其與最後一個元素Array[n-1]交換,這樣最大元素就放到了最後一個位子,接下來就可以把它剔除了,n–1,將剛剛的Arrayn-1在新的最大堆(元素少了一個,挑一個最大的出來)中找到合適的位置。

相當於第一次建立最大堆是建立,剩下的每次都是修補,將交換的元素找到一個合適的位置,這樣每次Array[0]又成了最大元素

//偽代碼片段

Heap_Sort(A)
  Build_Max_Heap(A)
  for i=A.length downto 2
     exchange A[1] with A[i]
     A.heap-size=A.heap-size - 1
     Max_Heapify(A,1)

  這是基於最大堆排序,結果是從小到大,因為最大的元素放在數組末尾,最小堆排序相反,但原理一樣

public class 堆排序 {
    // 先建堆

    public static void main(String[] args) {
        int Array[] = { 16, 14, 10, 8, 7, 9, 3, 2, 4, 1 };
        System.out.print("構建最大堆之前: ");
        for (int m : Array) {
            System.out.print(" " + m);
        }
        System.out.println("");
        Heap_Sort(Array);
        System.out.print("堆排序完成之後: ");
        for (int m : Array) {
            System.out.print(" " + m);
        }

    }

    public static void Heap_Sort(int Array[]) {
        int m_size = Array.length - 1;
        // Build_Max_Heapify(),將使A[0]達到最大值。這樣一直循環交換存放在數組A[i]中,遞歸調用。
        Build_Max_Heapify(Array);// 堆排序算法利用Build_Max_Heapify(Array)將數組Array建成最大堆
        System.out.print("構建最大堆之後: ");
        for (int m : Array) {
            System.out.print(" " + m);
        }
        System.out.println("");
        for (int i = m_size; i >= 1; i--) {
            Array[i] += Array[0]; // 因為數組中的最大元素總在根結點Array[0],與Array[m_size}交換,相當於將該節點已經確定出位置,接下來的排序可以不用再考慮該元素(它已經有了最後的位置)
            Array[0] = Array[i] - Array[0];
            Array[i] -= Array[0];
            // swap(A[0], A[i]);
            --m_size;// 剔除剛剛交換的Array[m_size]
            Max_Heapify(Array, 0,m_size);// 再構建最大堆,在原有的最大堆基礎之上亂了一個Array[0],找到Array[0]的位置,又是一個新的最大堆(少了剛剛那個確立的最大元素)
        }
    }

    public static void Build_Max_Heapify(int A[]) { // 建堆:子數組A[n/2+1...n]中的元素都是葉子節點,因此每個都可以看作只含一個元素的堆.
        int m_size = A.length - 1;                  // m_size/2與m_size一樣都正確,也就是上面句子的解釋。
        for (int i = m_size / 2; i >= 0; i--)
            Max_Heapify(A, i,m_size);
    }

    public static void Max_Heapify(int Array[], int i,int needSize) {
        int m_size = needSize;
        int largest;
        int left = Left(i);
        int right = Right(i);

        if ((left <= m_size) && (Array[left] > Array[i]))
            largest = left;
        else
            largest = i;
        if ((right <= m_size) && (Array[right] > Array[largest]))
            largest = right;
        if (largest != i) {
            Array[i] += Array[largest]; // 第一次交換確立最大元素Array[largest]
            Array[largest] = Array[i] - Array[largest];
            Array[i] -= Array[largest];
            Max_Heapify(Array, largest,m_size); // 將剛剛與最大元素交換的元素Array[i]在最大堆中找到一個合適的位置
        }

    }

    int Parent(int i) { // Parent node
        return i / 2;
    }

    static int Right(int i) { // right node
        return 2 * i + 2;
    }

    static int Left(int i) { // left node
        return 2 * i + 1;
    }

}

  

算法排序之堆排序