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)