Heap Sort

2 阅读3分钟

Code:

Basic Heap Sort

    template<typename Item>
    class MaxHeap {
        private:
            Item *data;
            int count;
            int capacity;
        
        void shiftUp(int k) {  
            while(data[k/2] < data[k]) {
                swap(data[k/2], data[k]);
                k /= 2;
            }
        }
        
        void shiftDown(int k) { 
            assert(2*k <= count);
            while(2*k <= count) {
                int j = 2*k;
                if(j+1 <= count && data[j] < data[j+1] ) {
                    j++;
                }
                if(data[k] < data[j]) {
                    swap(data[k], data[j]);
                } else {
                    break;
                }
                k= j;
            }
        }
        
        public:
            MaxHeap(int capacity) {
                data = new Item[capacity+1];
                count = 0;
                this->capacity = capacity;
            }
            
            MaxHeap(Item arr[], int n) {
                data = new Item[n+1];
                capacity = n;
                
                for(int i=0; i<n; i++) {
                    data[i+1] = arr[i];
                }
                
                count = n;
                
                for(int i=count/2; i>=1; i--) {
                    shiftDown(i);
                }
                
            }
            
            ~MaxHeap() {
                delete[] data;
            }
            
            int size() {
                return count;
            }
            
            bool isEmpty() {
                return count == 0;
            }
            
            void insert(Item item) {
                assert(count+1 <= capacity);
                data[count+1] = item;
                shiftUp(count+1);
                count ++;
            }
            
            Item extraMaxItem() {
                assert(count > 0);
                Item ret = data[1];
                swap(data[1], data[count]);
                count--;
                shiftDown(1);
                return ret;
            }
            
    }

The basic heap sort has main issues:

When the stored element occupy a large amount of memory, swapping elements during the sorting process will lead to perfacemance problems; To address this, the index Heap Sort algorithm was introduced. Furthermore, to optimize Index Heap Sort--specifically the need to traverse the Index array when modifying an element at a spacific position--a Reverse array is used to store the index of elements in the Index array, enabling O(1) complexity for lookup operations.

Code: Index Heap Sort

template<typename Item>
class IndexMaxHeap{

private:
    Item *data;     // Data stored in the Max Index Heap  
    int *indexes;   // Index array in the Max Index Heap: indexes[x] = i means the element with index i is at position x  
    int *reverse;   // Reverse index array in the Max Index Heap: reverse[i] = x means the element with index i is at position x  

    int count;
    int capacity;

    // In the index heap, comparisons between elements are based on the values in the data array,  
    // but the operations are actually performed on the indexes.
    void shiftUp( int k ){

        while( k > 1 && data[indexes[k/2]] < data[indexes[k]] ){
            swap( indexes[k/2] , indexes[k] );
            reverse[indexes[k/2]] = k/2;
            reverse[indexes[k]] = k;
            k /= 2;
        }
    }

    // In the index heap, comparisons between elements are based on the values in the data array,  
    // but operations are performed on the indexes.
    void shiftDown( int k ){

        while( 2*k <= count ){
            int j = 2*k;
            if( j + 1 <= count && data[indexes[j+1]] > data[indexes[j]] )
                j += 1;

            if( data[indexes[k]] >= data[indexes[j]] )
                break;

            swap( indexes[k] , indexes[j] );
            reverse[indexes[k]] = k;
            reverse[indexes[j]] = j;
            k = j;
        }
    }

public:
    // Constructor: creates an empty index heap that can hold up to 'capacity' elements
    IndexMaxHeap(int capacity){

        data = new Item[capacity+1];
        indexes = new int[capacity+1];
        reverse = new int[capacity+1];
        for( int i = 0 ; i <= capacity ; i ++ )
            reverse[i] = 0;

        count = 0;
        this->capacity = capacity;
    }

    ~IndexMaxHeap(){
        delete[] data;
        delete[] indexes;
        delete[] reverse;
    }

    // Returns the number of elements in the index heap
    int size(){
        return count;
    }

    // Returns a boolean indicating whether the index heap is empty
    bool isEmpty(){
        return count == 0;
    }

     // Inserts a new element into the max index heap, with index i and value item  
    // The passed index i is zero-based from the user's perspective
    void insert(int i, Item item){
        assert( count + 1 <= capacity );
        assert( i + 1 >= 1 && i + 1 <= capacity );
        
        // Before inserting a new element, ensure that the position corresponding to index i is  not already occupied.
        assert( !contain(i) );

        i += 1;
        data[i] = item;
        indexes[count+1] = i;
        reverse[i] = count+1;
        count++;

        shiftUp(count);
    }

    // Extracts the top element from the max index heap, i.e., the maximum data stored in the index heap
    Item extractMax(){
        assert( count > 0 );

        Item ret = data[indexes[1]];
        swap( indexes[1] , indexes[count] );
        reverse[indexes[count]] = 0;
        count--;

        if(count){
            reverse[indexes[1]] = 1;
            shiftDown(1);
        }

        return ret;
    }

    // Extracts the index of the top element from the max index heap
    int extractMaxIndex(){
        assert( count > 0 );

        int ret = indexes[1] - 1;
        swap( indexes[1] , indexes[count] );
        reverse[indexes[count]] = 0;
        count--;

        if(count) {
            reverse[indexes[1]] = 1;
            shiftDown(1);
        }

        return ret;
    }

    // Retrieves the top element from the max index heap
    Item getMax(){
        assert( count > 0 );
        return data[indexes[1]];
    }

    // Retrieves the index of the top element in the max index heap
    int getMaxIndex(){
        assert( count > 0 );
        return indexes[1]-1;
    }

    // Checks whether there is an element at the position corresponding to index i
    bool contain( int i ){
        assert( i + 1 >= 1 && i + 1 <= capacity );
        return reverse[i+1] != 0;
    }

    // Retrieves the element with index i from the max index heap
    Item getItem( int i ){
        assert( contain(i) );
        return data[i+1];
    }

    // Modifies the element with index i in the max index heap to newItem
    void change( int i , Item newItem ){
        assert( contain(i) );
        i += 1;
        data[i] = newItem;
        // With the reverse array, we can easily locate the position of index i in the indexes array directly through reverse
        shiftUp( reverse[i] );
        shiftDown( reverse[i] );
    }
};    

Analysis of Algorithm Complexity:

  • Time Complexity of the Algorithm: O(nlogn)

  • Space Complexity of the Algorithm: O(1)