// Cleanup a heap void heap_destroy(heap* h) { // Check that h is not null assert(h != NULL); // Map out the table map_out_pages(h->table, h->allocated_pages); // Clear everything h->active_entries = 0; h->allocated_pages = 0; h->table = NULL; }
// Cleanup a heap void heap_destroy(heap* h) { // Check that h is not null assert(h != NULL); // Un-map all the entry pages void** map_table = h->mapping_table; assert(map_table != NULL); for (int i=0; i < h->allocated_pages; i++) { map_out_pages(*(map_table+i),1); } // Map out the map table map_out_pages(map_table, h->map_pages); // Clear everything h->active_entries = 0; h->allocated_pages = 0; h->map_pages = 0; h->mapping_table = NULL; }
// Deletes the minimum entry in the heap int heap_delmin(heap* h, void** key, void** value) { // Check there is a minimum if (h->active_entries == 0) return 0; // Load in the map table heap_entry* table = h->table; // Get the root element int current_index = 0; heap_entry* current = GET_ENTRY(current_index, table); // Store the outputs if (key) *key = current->key; if (value) *value = current->value; // Reduce the number of active entries h->active_entries--; // Get the active entries int entries = h->active_entries; // If there are any other nodes, we may need to move them up if (h->active_entries > 0) { // Move the last element to the root heap_entry* last = GET_ENTRY(entries,table); current->key = last->key; current->value = last->value; // Loop variables heap_entry* left_child; heap_entry* right_child; // Load the comparison function int (*cmp_func)(void*,void*) = h->compare_func; // Store the left index int left_child_index; while (left_child_index = LEFT_CHILD(current_index), left_child_index < entries) { // Load the left child left_child = GET_ENTRY(left_child_index, table); // We have a left + right child if (left_child_index+1 < entries) { // Load the right child right_child = GET_ENTRY((left_child_index+1), table); // Find the smaller child if (cmp_func(left_child->key, right_child->key) <= 0) { // Swap with the left if it is smaller if (cmp_func(current->key, left_child->key) == 1) { SWAP_ENTRIES(current,left_child); current_index = left_child_index; current = left_child; // Otherwise, the current is smaller } else break; // Right child is smaller } else { // Swap with the right if it is smaller if (cmp_func(current->key, right_child->key) == 1) { SWAP_ENTRIES(current,right_child); current_index = left_child_index+1; current = right_child; // Current is smaller } else break; } // We only have a left child, only do something if the left is smaller } else if (cmp_func(current->key, left_child->key) == 1) { SWAP_ENTRIES(current,left_child); current_index = left_child_index; current = left_child; // Done otherwise } else break; } } // Check if we should release a page of memory int used_pages = entries / ENTRIES_PER_PAGE + ((entries % ENTRIES_PER_PAGE > 0) ? 1 : 0); // Allow one empty page, but not two if (h->allocated_pages / 2 > used_pages + 1 && h->allocated_pages / 2 >= h->minimum_pages) { // Get the new number of entries we need int new_size = h->allocated_pages / 2; // Map in a new table heap_entry* new_table = map_in_pages(new_size); // Copy the old entries, copy the entire pages memcpy(new_table, h->table, used_pages*PAGE_SIZE); // Cleanup the old table map_out_pages(h->table, h->allocated_pages); // Switch to the new table h->table = new_table; h->allocated_pages = new_size; } // Success return 1; }
// Insert a new element void heap_insert(heap *h, void* key, void* value) { // Check if this heap is not destoyed assert(h->table != NULL); // Check if we have room int max_entries = h->allocated_pages * ENTRIES_PER_PAGE; if (h->active_entries + 1 > max_entries) { // Get the new number of entries we need int new_size = h->allocated_pages * 2; // Map in a new table heap_entry* new_table = map_in_pages(new_size); // Copy the old entries, copy the entire pages memcpy(new_table, h->table, h->allocated_pages*PAGE_SIZE); // Cleanup the old table map_out_pages(h->table, h->allocated_pages); // Switch to the new table h->table = new_table; h->allocated_pages = new_size; } // Store the comparison function int (*cmp_func)(void*,void*) = h->compare_func; // Store the table address heap_entry* table = h->table; // Get the current index int current_index = h->active_entries; heap_entry* current = GET_ENTRY(current_index, table); // Loop variables int parent_index; heap_entry *parent; // While we can, keep swapping with our parent while (current_index > 0) { // Get the parent index parent_index = PARENT_ENTRY(current_index); // Get the parent entry parent = GET_ENTRY(parent_index, table); // Compare the keys, and swap if we need to if (cmp_func(key, parent->key) < 0) { // Move the parent down current->key = parent->key; current->value = parent->value; // Move our reference current_index = parent_index; current = parent; // We are done swapping } else break; } // Insert at the current index current->key = key; current->value = value; // Increase the number of active entries h->active_entries++; }
// Deletes the minimum entry in the heap int heap_delmin(heap* h, void** key, void** value) { // Check there is a minimum if (h->active_entries == 0) return 0; // Load in the map table void** map_table = h->mapping_table; // Get the root element int current_index = 0; heap_entry* current = GET_ENTRY(current_index, map_table); // Store the outputs if (key != NULL && value != NULL) { *key = current->key; *value = current->value; } // Reduce the number of active entries h->active_entries--; // Get the active entries int entries = h->active_entries; // If there are any other nodes, we may need to move them up if (h->active_entries > 0) { // Move the last element to the root heap_entry* last = GET_ENTRY(entries,map_table); current->key = last->key; current->value = last->value; // Loop variables heap_entry* left_child; heap_entry* right_child; // Load the comparison function int (*cmp_func)(void*,void*) = h->compare_func; // Store the left index int left_child_index; while (left_child_index = LEFT_CHILD(current_index), left_child_index < entries) { // Load the left child left_child = GET_ENTRY(left_child_index, map_table); // We have a left + right child if (left_child_index+1 < entries) { // Load the right child right_child = GET_ENTRY((left_child_index+1), map_table); // Find the smaller child if (cmp_func(left_child->key, right_child->key) <= 0) { // Swap with the left if it is smaller if (cmp_func(current->key, left_child->key) == 1) { SWAP_ENTRIES(current,left_child); current_index = left_child_index; current = left_child; // Otherwise, the current is smaller } else break; // Right child is smaller } else { // Swap with the right if it is smaller if (cmp_func(current->key, right_child->key) == 1) { SWAP_ENTRIES(current,right_child); current_index = left_child_index+1; current = right_child; // Current is smaller } else break; } // We only have a left child, only do something if the left is smaller } else if (cmp_func(current->key, left_child->key) == 1) { SWAP_ENTRIES(current,left_child); current_index = left_child_index; current = left_child; // Done otherwise } else break; } } // Check if we should release a page of memory int used_pages = entries / ENTRIES_PER_PAGE + ((entries % ENTRIES_PER_PAGE > 0) ? 1 : 0); // Allow one empty page, but not two if (h->allocated_pages > used_pages + 1 && h->allocated_pages > h->minimum_pages) { // Get the address of the page to delete void* addr = *(map_table+h->allocated_pages-1); // Map out map_out_pages(addr, 1); // Decrement the allocated count h->allocated_pages--; } // Success return 1; }
// Insert a new element void heap_insert(heap *h, void* key, void* value) { // Check if this heap is not destoyed assert(h->mapping_table != NULL); // Check if we have room int max_entries = h->allocated_pages * ENTRIES_PER_PAGE; if (h->active_entries + 1 > max_entries) { // Get the number of map pages int map_pages = h->map_pages; // We need a new page, do we have room? int mapable_pages = map_pages * PAGE_SIZE / sizeof(void*); // Check if we need to grow the map table if (h->allocated_pages + 1 > mapable_pages) { // Allocate a new table, slightly bigger void *new_table = map_in_pages(map_pages + 1); // Get the old table void *old_table = (void*)h->mapping_table; // Copy the old entries to the new table memcpy(new_table, old_table, map_pages * PAGE_SIZE); // Delete the old table map_out_pages(old_table, map_pages); // Swap to the new table h->mapping_table = (void**)new_table; // Update the number of map pages h->map_pages = map_pages + 1; } // Allocate a new page void* addr = map_in_pages(1); // Add this to the map *(h->mapping_table+h->allocated_pages) = addr; // Update the number of allocated pages h->allocated_pages++; } // Store the comparison function int (*cmp_func)(void*,void*) = h->compare_func; // Store the map table address void** map_table = h->mapping_table; // Get the current index int current_index = h->active_entries; heap_entry* current = GET_ENTRY(current_index, map_table); // Loop variables int parent_index; heap_entry *parent; // While we can, keep swapping with our parent while (current_index > 0) { // Get the parent index parent_index = PARENT_ENTRY(current_index); // Get the parent entry parent = GET_ENTRY(parent_index, map_table); // Compare the keys, and swap if we need to if (cmp_func(key, parent->key) < 0) { // Move the parent down current->key = parent->key; current->value = parent->value; // Move our reference current_index = parent_index; current = parent; // We are done swapping } else break; } // Insert at the current index current->key = key; current->value = value; // Increase the number of active entries h->active_entries++; }