1. 程式人生 > >圖解-堆排序 in-place Heap Sort

圖解-堆排序 in-place Heap Sort

轉自:http://www.mathcs.emory.edu/~cheung/Courses/171/Syllabus/9-BinTree/heap-sort2.html

 

  • Short-coming of the previous "simple" Heap Sort algorithm

     

    • Consider the (previously discussed) simple Heap Sort algorithm:

       

         public static void main(String[] args)
         {
            Scanner in = new Scanner(System.in);
            double  a[] = {9.2, 4.2, 1.1, 6.4, 3.5, 8.9, 2.5, 7.5}
      ; // Array 1 Heap x = new Heap( 100 ); // Array 2 for ( int i = 0; i < a.length; i++ ) { System.out.println("Insert: " + a[i] ); x.put( a[i] ); x.printHeap(); } System.out.println("\n\nKeep removing the first node : "); for ( int i = 0; i < a.length; i++ ) { double r; r = x.remove(1); System.out.print( r + ", "); } System.out.println(); }

      This algorithm uses 2 (two) arrays:

       

      • The array a[ ] to store the data that we want to sort

         


         

      • The Heap data structure (that we create
         with the new Heap(100)also uses an array !!!

       



       

    • Idea:

       

      • Can we use the input array a[ ] as a Heap ???

        In other words:

         

        • Can we apply the heap insert/delete algorithm directly on the array a[ ] ???

         

       

     





     

  • Input data assumption

     

    • Facts:

       

      • The input data that will be sorted are normally stored in an array that starts with the index 0 in Java

         


         

      • However:

         

        • When we use an array to represent a Heap, we leave the array element a[0] unused (empty)...

         

       


       

    • We adopt the following assumption on the input data (that we want to sort) in the Heap Sort algorithm:

       

      • The input data that will be sorted are stored in an array that starts with the index 1        

        (I.e., the array element a[0] is not used)

      Example:

       

      • If we want to sort the values:

         

            9.2, 4.2, 1.1, 6.4, 3.5, 8.9, 2.5, 7.5                 
        

        we will use an array with a dummy value in a[0]:

         

           double[] a = { 0.0, 9.2, 4.2, 1.1, 6.4, 3.5, 8.9, 2.5, 7.5};   
        

         

       

     





     

  • Overview of the in-place Heap Sort algorithm

     

    • The in-place Heap Sort algorithm consists of 2 phases:

       

      1. Heap building (insert) phase:

         

        • In this phase, the input array is slowly transformed into a Heap --- one array element at a time.

         


         

      2. Heap teardown (delete) phase:

         

        • In this phase, the root node of the Heap is moved to the back of the array and the heap is torn down, one array element at a time.

         

       

     





     

  • Heap Sort Phase 1: building an in-place heap

     

    • I will illustrate the Phase 1 algorithm with an example:

       

         Input array:
      
           a = { 0.0, 9.2, 4.2, 1.1, 6.4, 3.5, 8.9, 2.5, 7.5};    
      

       


       

    • We pretend that the input array is partitioned into 2 segments:

       

      • heap segment consisting of the array elements:

         

           a[1] a[2] .... a[k]          
        

        that form a Heap

         


         

      • unprocessed segment of unprocessed array elements:

         

           a[k+1] a[k+2] .... a[N]        
        

         

       


       

    • Initially, the heap segments consists of only one array element (a[0]):

       

       



       

    • I will now do a few iterations of the Phase 1 algorithm:

       

      • Iteration 1:

         

        • Step 1: add the next array element (a[2] = 4.2) to the Heap

           

           


           

        • Step 2: Filter the newly added next array element (a[2] = 4.2) up into the Heap

           

           

         



         

      • Iteration 2:

         

        • Step 1: add the next array element (a[3] = 1.1) to the Heap

           

           


           

        • Step 2: Filter the newly added next array element (a[3] = 1.1) up into the Heap

           

           

         



         

      • One more and I will stop, Iteration 3:

         

        • Step 1: add the next array element (a[4] = 6.4) to the Heap

           

           


           

        • Step 2: Filter the newly added next array element (a[4] = 6.4) up into the Heap

           

           

         

       




       

       

    • The Phase 1 of the Heap Sort algorithm:

       

            // Initially: heap segment = {a[1]}
      
            for ( every element x = a[2], a[3], a[4], .... )
            {
                "Include x into the Heap;"  // We don't need to do anything !!!
                                            // We just pretend the heap segment      
                                            // has expanded by 1 array element
      
                filter x up the heap;
            }
      

       



       

    • The Phase 1 algorithm in Java:

       

            NNodes = 1;              // Start the Heap with a[1]
      
            for (i = 2; i < a.length; i++)
            {
               NNodes++;                  // "Include" the next node              
      
               HeapFilterUp(a, NNodes);   // Filter a[NNodes] up the heap.      
            }
      

       

       

     





     

  • The result of the Phase 1 algorithm

     

    • Fact:

       

      • When Phase 1 of the Heap Sort algorithm completes, the input array (a[ ]) will be transformed into a Heap

       


       

    • Example:

       

      • Initial input array:

         

         


         

      • When phase 1 completes, the input array will be a Heap:

         

         

       

     





     





     

  • Heap Sort Pase 2: tearing down the in-place heap

     

    • In Phase 2, we repeatedly remove the root node of the (in-place) heap

       

      • The root node of the Heap is (always) stored in the array element a[1]

        Example:

         

         

       


       

    • Recall:

       

      • When we delete a node from the Heap, we must first:

         

        • Replace the deleted node with the right-most leaf node in the lowest level

        Example:

         

        • When we delete the root node 1.1:

           

           


           

        • We first replace the root node with the node 6.4:

           

           

         

       



       

    • The Heap deletion algorithm will then use the filter down algorithm to transform the tree into a Heap

      (Remember that in a Heap, the root node of each subtree must have the smallest value in its subtree -

      The filter down algorithm will fix the tree to comply with this property)

       

      • We can (and will) apply the filter down algorithm to fix the tree...

        (We will discuss that later...)

        But more importantly, notice that:

         

        The array has a empty slot at the end !!!

         

        • We can use this empty slot to store the deleted value (1.1) !!!

          (This trick makes the Heap Sort algorithm an in-place algorithm --- we don't need another array !!!)

         

       

       




       

    • This is what I mean:

       

      • We store the deleted value into the empty slot created by the replacement step of the Heap deletion algorithm:

         

         

       



       

    • Now we perform the filter down algorithm to fix the Heap:

       

      • Initially:

         

         


         

      • Filter downswap with the smallest child node

         

        Result:

         

         



         

      • Since 6.4 is smaller than its children nodes (9.2 and 7.5), we have a Heap again.

       



       

    • I will now do one more iteration of the Phase 2 algorithm (starting with the last result):

       

      • Iteration 2: (the previous iteration was the first iteration !)

         

        • Initially:

           

           


           

        • Delete the root node (a[1]):

           

          (We save the deleted value in a help variable)

           


           

        • Replace the root node with the fartest right node on the lowest levl:

           

          (We save the deleted value in a help variable)

           


           

        • Save the deleted value in the empty slot: (this slot is not part of the Heap !!!)

           

           


           

        • Fix the Heap using the filter down algorithm:

          Exchange the replacement node with its smallest child:

           

          Result:

           

           

          Exchange again: (because one of its child node is smaller)

           

          Result:

           

           

         

         

       



       

    • Notice that:

       

      • The value is sorted backwards in the back of the array !!!

        Example:

         

         

       



       

    • Phase 2 algorithm in Pseudo code:

       

         repeat these step N times (N = # nodes in the heap)
         {
            help = a[1];       // Delete the root node and save the value
      
            a[1] = a[last node in heap];  // Replace root node with
                                          // fartest right node on lowest level    
      
            a[empty slot] = help;         // Save deleted value in empty slot
      
             HeapFilterUp( 1 );           // Fix the heap start at root node
         }
      
         // Optionally, we can reverse the
         // array elements (because the values are sorted in reverse order) 
      

       



       

    • Phase 2 algorithm in Java:

       

            for ( i = 1; i < a.length; i++ )
            {
               help = a[1];	    // Delete root node
      
      	 a[1] = a[NNodes];  // Replace root node with the last node
      
               a[NNodes] = help;  // Put the deleted node in the empty slot
      
               NNodes--;          // One less node in Heap 
      
      	 HeapFilterDown(a, 1, NNodes);   // Fix the Heap
            }
      
            /* =========================================================
               This for-loop reverse the elements a[1] a[2] ... a[N]
      	 ========================================================= */      
            for ( i = 1, j = a.length-1; i < j; i++, j-- )
            {
               help = a[i];
               a[i] = a[j];
               a[j] = help;
            }
      

       

     





     

  • The complete Heap Sort algorithm

     

    • Putting phase 1 and phase 2 into the sort method yields the following code:

       

         public static void sort( double[] a )
         {
            int i, j, NNodes;
            double help;
      
            /* =======================================
               Phase 1
      	 ======================================= */
            NNodes = 1;
            for (i = 2; i < a.length; i++)
            {
             	 NNodes++;		 // include next node
      	 HeapFilterUp(a, NNodes);
      	 printHeap(a, NNodes);
            }
      
            /* =======================================
               Phase 2
      	 ======================================= */
            for ( i = 1; i < a.length; i++ )
            {
               help = a[1];	    // Delete root node
      
      	 a[1] = a[NNodes];  // Replace root node with the last node
      
               a[NNodes] = help;  // Put the deleted node in the empty slot
      
               NNodes--;          // One less node in Heap 
      
      	 HeapFilterDown(a, 1, NNodes);   // Fix the Heap
      
               printHeap(a, NNodes);
            }
      
            /* =======================================
               Reverse the (sorted) array
      	 ======================================= */
            for ( i = 1, j = a.length-1; i < j; i++, j-- )
            {
               help = a[i];
               a[i] = a[j];
               a[j] = help;
            }
      
         }
      

       



       

    • The Filter Up method has been changed a little (because we must pass the array as a parameter)

       

         The array a is passed as parameter
         The parameter k also to tell the method how many nodes
            there are in the Heap
      
         public static void HeapFilterUp( double[] a, int k )              
         {
      
            **** The BODY of the method is UNCHANGED !!!! ****
      
         }
      

      (The algorithm did not change. --- that's why I did not include the body)

      Only the way that the array is given to the method was changed

      This change does not (and should not) affect you understanding of the algorithm !!!)

       



       

    • The Filter Down method is also change a little bit due to the way the parameters are passed:

       

         The array a is passed as parameter
         The parameter NNodes is also needed to tell the method how many nodes
           there are in the Heap
         (k is the index of the delete location)
      
         public static void HeapFilterDown( double[] a, int k, int NNodes )
         {
      
            **** The BODY of the method is UNCHANGED !!!! ****
      
         }
      

       



       

    • Here is a test program for the Heap Sort method:

       

         public static void main( String[] args )
         {
            double[] x = {0, 6.4, 2.5, 9.2, 3.5, 8.9, 1.1, 7.5, 4.2} ;
      
            System.out.println("Before sort:  " + Arrays.toString(x) + "\n" );    
      
            HeapSort.sort( x );  // Heap sort
      
            System.out.println("\nAfter sort:   " + Arrays.toString(x) );
         }
      

      Output:

       

      After sort:   [0.0, 1.1, 2.5, 3.5, 4.2, 6.4, 7.5, 8.9, 9.2]      
      

       


       

    • Example Program: (Demo above code)                                                 

       

      How to run the program:

       

      • Right click on link and save in a scratch directory

         

      • To compile:   javac testProg.java
      • To run:          java testProg