-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from IgooorGP/feature/add-sorting
Feature/add sorting
- Loading branch information
Showing
7 changed files
with
308 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/** | ||
* @file strukts_heap.h | ||
* | ||
* @brief Module that contains heap implementations. | ||
* | ||
* Binary heaps are ARRAY objects that represent binary trees and, as such, can provide | ||
* efficient operations. There are two types of binary heaps: | ||
* | ||
* - max-heap: the root contains the largest element: a[parent(i)] >= a[i] | ||
* - min-heap: the root contains the smallest element: a[parent(i)] <= a[i] | ||
*/ | ||
|
||
#ifndef STRUKTS_HEAP_H | ||
#define STRUKTS_HEAP_H | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#include <stdbool.h> | ||
#include <stdlib.h> | ||
|
||
/********************** MACROS **********************/ | ||
#define SWAP(arr, i, j) \ | ||
int old = arr[i]; \ | ||
arr[i] = arr[j]; \ | ||
arr[j] = old | ||
|
||
/** | ||
* Represents a max-heap data structure in which an array can be viewed as a binary tree. | ||
*/ | ||
typedef struct _StruktsMaxHeap StruktsMaxHeap; | ||
|
||
struct _StruktsMaxHeap { | ||
int* array; /* pointer to a heap array */ | ||
size_t size; | ||
}; | ||
|
||
/** | ||
* Represents child metadata of some parent node. If the result is within | ||
* the heap array's bondaries, valid = true. Otherwise, valid = false. | ||
*/ | ||
typedef struct _StruktsHeapChildResult StruktsHeapChildResult; | ||
|
||
struct _StruktsHeapChildResult { | ||
int value; | ||
size_t position; | ||
bool valid; | ||
}; | ||
|
||
/** | ||
* Builds a new binary heap (max-heap) from a given array in-place. This method mutates | ||
* the array contents to organize it according to the rules of a max-heap. | ||
* | ||
* @param a is the array in which the heap will be built upon; | ||
* @param len is the size of the array; | ||
* | ||
* @return a struct of a max-heap. | ||
*/ | ||
StruktsMaxHeap strukts_heap_maxheap_new(int a[], size_t len); | ||
|
||
/** | ||
* Gets the left (or right) child of a given parent node which is in index i. If the given parent | ||
* node would have children beyond the array's bondaries, the StruktsHeapChildResult will contain | ||
* the property 'valid' set to false. Otherwise, 'valid' is set to true and the child is in the | ||
* heap. Roughly works like a 'maybe' monad. | ||
* | ||
* @param heap is a max-heap struct. | ||
* @param parent_i is the index of the parent node whose child will be searched for. | ||
* @param left_child boolean which indicates to get the left child; if false, returns the right | ||
* child. | ||
* | ||
* @return StruktsHeapChildResult struct which will contain metadata of the child such as its value, | ||
* its position and whether this is a valid result or not (within the bondaries of the array of the | ||
* heap). If valid is set to false, both the value and position should not be used. | ||
*/ | ||
StruktsHeapChildResult strukts_heap_get_child(StruktsMaxHeap heap, size_t parent_i, | ||
bool left_child); | ||
|
||
/** | ||
* Gets the parent's value of a given child node that can be found in index i. | ||
* | ||
* @param heap is a max-heap struct. | ||
* @param child_i is the index of the child node whose parent will be searched for. | ||
* | ||
* @return the value of the parent node. | ||
*/ | ||
int strukts_heap_get_parent(StruktsMaxHeap heap, size_t child_i); | ||
|
||
/** | ||
* Heapifies (mutates) the heap's array in order to guarantee the max-heap structure in which | ||
* any parent is always bigger/equal than its children. Hence: | ||
* | ||
* - heap->array[parent(i)] >= heap->array[i] | ||
* | ||
* Heapifying can start from any index i. If i = 0 (root), then it heapifies the whole array | ||
* (tree). | ||
* | ||
* @param heap is a max-heap struct. | ||
* @param parent_i is the index of the desired 'parent node' to begin heapifying from. | ||
*/ | ||
void strukts_heap_max_heapify(StruktsMaxHeap heap, size_t parent_i); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
#endif /* STRUKTS_HEAP_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
#include "strukts_heap.h" | ||
|
||
#include <limits.h> | ||
#include <stdbool.h> | ||
#include <stdlib.h> | ||
|
||
/********************** PUBLIC FUNCTIONS **********************/ | ||
StruktsMaxHeap strukts_heap_maxheap_new(int a[], size_t len) | ||
{ | ||
StruktsMaxHeap max_heap = {.array = a, .size = len}; | ||
|
||
/* | ||
* Heapifies the whole array. Notice that there's no need to go beyond | ||
* the middle of the array (parent_i = len / 2), as heapifying requires | ||
* fetching children from each parent and as children stay, roughly, | ||
* at the index (2 * parent_i), these children would be invalid as they | ||
* would be outside the heap array size boundaries. | ||
* | ||
* The loop uses a trick to avoid underflow of a size_t which is always >= 0. | ||
*/ | ||
for (size_t i = 0; i <= len / 2; i++) { | ||
size_t parent_i = len / 2 - i; /* trick for reverse iterating with size_t */ | ||
strukts_heap_max_heapify(max_heap, parent_i); | ||
} | ||
|
||
return max_heap; | ||
} | ||
|
||
StruktsHeapChildResult strukts_heap_get_child(StruktsMaxHeap heap, size_t parent_i, bool left_child) | ||
{ | ||
StruktsHeapChildResult result = {.valid = false, .value = 0, .position = 0}; | ||
size_t child_position; | ||
|
||
if (left_child) | ||
child_position = 2 * parent_i + 1; | ||
else | ||
child_position = 2 * parent_i + 2; | ||
|
||
result.position = child_position; | ||
|
||
/* index goes beyond the heap array's final index (size - 1): return invalid result */ | ||
if (child_position > heap.size - 1) | ||
return result; | ||
|
||
result.value = heap.array[child_position]; | ||
result.valid = true; | ||
|
||
return result; | ||
} | ||
|
||
int strukts_heap_get_parent(StruktsMaxHeap heap, size_t child_i) | ||
{ | ||
if (child_i % 2 == 0) /* even indexes */ | ||
return heap.array[child_i / 2 - 1]; | ||
|
||
return heap.array[child_i / 2]; | ||
} | ||
|
||
void strukts_heap_max_heapify(StruktsMaxHeap heap, size_t parent_i) | ||
{ | ||
StruktsHeapChildResult left_child = strukts_heap_get_child(heap, parent_i, true); | ||
StruktsHeapChildResult right_child = strukts_heap_get_child(heap, parent_i, false); | ||
size_t largest_i = 0; | ||
|
||
/* | ||
* Compares the parent, heap.array[parent_i], against its children nodes. Here the | ||
* biggest wins (parent, left or right child). If any of the children is bigger than | ||
* its parent, then the parent is swapped with its child and heapify is recursively | ||
* called on the parent's new position (to continue to make sure the max-heap is respected). | ||
*/ | ||
if (left_child.valid && left_child.value > heap.array[parent_i]) | ||
largest_i = left_child.position; | ||
else | ||
largest_i = parent_i; /* parent is bigger than left child */ | ||
|
||
if (right_child.valid && right_child.value > heap.array[largest_i]) | ||
largest_i = right_child.position; /* right child is the biggest one */ | ||
|
||
/* one of the children is bigger than the parent: swap and keep heapifying */ | ||
if (largest_i != parent_i) { | ||
SWAP(heap.array, parent_i, largest_i); | ||
strukts_heap_max_heapify(heap, largest_i); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#include "gtest/gtest.h" | ||
#include "strukts_heap.h" | ||
|
||
namespace | ||
{ | ||
TEST(STRUKTS_HEAP_SUITE, SHOULD_BUILD_HEAP_FROM_ARRAY) | ||
{ | ||
/* arrange */ | ||
int a[] = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7}; | ||
size_t len = 10; | ||
|
||
/* act */ | ||
StruktsMaxHeap heap = strukts_heap_maxheap_new(a, len); | ||
|
||
/* assert */ | ||
int expected[] = {16, 14, 10, 8, 7, 9, 3, 2, 4, 1}; | ||
|
||
EXPECT_TRUE(0 == memcmp(heap.array, expected, len * sizeof(int))); | ||
} | ||
} // namespace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters