add vec_shrink
This commit is contained in:
parent
ea2b8900dd
commit
203124ed6a
|
@ -0,0 +1,203 @@
|
|||
# binarytree
|
||||
|
||||
Binary tree with standard leaf operations
|
||||
|
||||
## Usage
|
||||
|
||||
Create the tree. The user is responsible for memory management of the `BinTree` struct.
|
||||
|
||||
```c
|
||||
BinTree *tree = malloc(sizeof(BinTree));
|
||||
```
|
||||
|
||||
After the tree is created, init it. The second argument on `bintree_init()` is an optional memory freeing function pointer
|
||||
with signature `void (*destroy)(void *data)`. Use `free()` from the stdlib if you are creating the data with `malloc()`.
|
||||
If allocation of your data is more complex, you can pass your own memory deallocation function as long as it fits the
|
||||
signature.
|
||||
|
||||
In this example, we are passing `NULL` because all memory will be stack allocated.
|
||||
|
||||
```c
|
||||
bintree_init(tree, NULL);
|
||||
int root = 0;
|
||||
int l1 = 1;
|
||||
int l2 = 2;
|
||||
int r1 = 12;
|
||||
int r2 = 200;
|
||||
```
|
||||
|
||||
Next lets insert our data into the tree. The insert functions signature is `bintree_ins_...(tree, parent, data)`. If you
|
||||
are inserting data at the root of the tree, you may use either `bintree_ins_left()` or `bintree_ins_right()` as long as
|
||||
`NULL` is passed as the parent argument.
|
||||
|
||||
```c
|
||||
bintree_ins_left(tree, NULL, &root);
|
||||
bintree_ins_left(tree, tree->root, &l1);
|
||||
bintree_ins_left(tree, tree->root->left, &l2);
|
||||
bintree_ins_right(tree, tree->root->left, &r2);
|
||||
bintree_ins_right(tree, tree->root, &r1);
|
||||
bintree_ins_right(tree, tree->root->right, &r2);
|
||||
bintree_ins_left(tree, tree->root->right, &l1);
|
||||
```
|
||||
|
||||
We can use `bintree_debug_print(tree)` to print a graphical representation of the tree to `stdout`
|
||||
```plaintext
|
||||
└──0
|
||||
├──1
|
||||
│ ├──2
|
||||
│ └──200
|
||||
└──12
|
||||
├──1
|
||||
└──200
|
||||
```
|
||||
|
||||
To cleanup the tree, first destroy the nodes. If you passed a deallocation function, it will be called on
|
||||
the data member of each node before the node itself is freed. `bintree_destroy()` does not free the tree itself, just the
|
||||
nodes inside of it, hence we must also call `free()` on the tree.
|
||||
|
||||
```c
|
||||
bintree_destroy(tree);
|
||||
free(tree);
|
||||
tree = NULL;
|
||||
```
|
||||
|
||||
Here is the entire example:
|
||||
|
||||
```c
|
||||
BinTree *tree = malloc(sizeof(BinTree));
|
||||
bintree_init(tree, NULL);
|
||||
|
||||
int root = 0;
|
||||
int l1 = 1;
|
||||
int l2 = 2;
|
||||
int r1 = 12;
|
||||
int r2 = 200;
|
||||
|
||||
bintree_ins_left(tree, NULL, &root);
|
||||
bintree_ins_left(tree, tree->root, &l1);
|
||||
bintree_ins_left(tree, tree->root->left, &l2);
|
||||
bintree_ins_right(tree, tree->root->left, &r2);
|
||||
bintree_ins_right(tree, tree->root, &r1);
|
||||
bintree_ins_right(tree, tree->root->right, &r2);
|
||||
bintree_ins_left(tree, tree->root->right, &l1);
|
||||
|
||||
bintree_debug_print(tree);
|
||||
|
||||
bintree_destroy(tree);
|
||||
free(tree);
|
||||
tree = NULL;
|
||||
```
|
||||
|
||||
## Structs
|
||||
|
||||
### BinTree
|
||||
|
||||
Binary tree struct
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
int size;
|
||||
int (*compare)(const void *a, const void *b);
|
||||
void (*destroy)(void *data);
|
||||
struct BinTreeNode *root;
|
||||
} BinTree;
|
||||
```
|
||||
|
||||
Members:
|
||||
|
||||
- `size`: How many nodes the tree contains
|
||||
- `compare`: Comparison function between data in two nodes. Currently not used for anything
|
||||
- `destroy`: Optional deallocation function for data inside a node. Typical usage is `NULL` for stack allocated data and `free()` for data created with `malloc()`
|
||||
- `root`: The root node of the tree
|
||||
|
||||
### BinTreeNode
|
||||
|
||||
Node of the tree
|
||||
|
||||
```c
|
||||
typedef struct BinTreeNode {
|
||||
void *data;
|
||||
struct BinTreeNode *left;
|
||||
struct BinTreeNode *right;
|
||||
} BinTreeNode;
|
||||
```
|
||||
|
||||
Members:
|
||||
- `data`: void pointer to data the node contains
|
||||
- `left`: left facing leaf of the node
|
||||
- `right`: right facing leaf of the node
|
||||
|
||||
## Functions
|
||||
|
||||
### bintree_init
|
||||
|
||||
Initialize the binary tree. User is responsible for freeing memory with `bintree_destroy()`.
|
||||
|
||||
```c
|
||||
void bintree_init(BinTree *tree, void (*destroy)(void *data))
|
||||
```
|
||||
|
||||
### bintree_destroy
|
||||
|
||||
Destroys the nodes inside a tree and calls the deallaction function on the data if one was provided. Does not deallocate
|
||||
the tree itself, that is left to the user.
|
||||
|
||||
```c
|
||||
void bintree_destroy(BinTree *tree)
|
||||
```
|
||||
|
||||
### bintree_ins_left
|
||||
|
||||
Creates a new node containing `data` and inserts it as the left child of `node`.
|
||||
|
||||
```c
|
||||
int bintree_ins_left(BinTree *tree, BinTreeNode *node, void *data)
|
||||
```
|
||||
|
||||
### bintree_ins_right
|
||||
|
||||
Creates a new node containing `data` and inserts it as the right child of `node`.
|
||||
|
||||
```c
|
||||
int bintree_ins_right(BinTree *tree, BinTreeNode *node, void *data)
|
||||
```
|
||||
|
||||
### bintree_rem_left
|
||||
|
||||
Removes and deallocates the left child node of `node`. Calls the deallocation function on the data if one was provided.
|
||||
|
||||
```c
|
||||
void bintree_rem_left(BinTree *tree, BinTreeNode *node)
|
||||
```
|
||||
|
||||
### bintree_rem_right
|
||||
|
||||
Removes and deallocates the right child node of `node`. Calls the deallocation function on the data if one was provided.
|
||||
|
||||
```c
|
||||
void bintree_rem_right(BinTree *tree, BinTreeNode *node)
|
||||
```
|
||||
|
||||
### bintree_debug_print
|
||||
|
||||
Prints a representation of the tree to stdout. Gets very messy with large trees.
|
||||
|
||||
```c
|
||||
void bintree_debug_print(BinTree *tree)
|
||||
```
|
||||
|
||||
### bintree_is_eob
|
||||
|
||||
Utility macro that checks if the node is the End Of Branch.
|
||||
|
||||
```c
|
||||
#define bintree_is_eob(node) ((node) == NULL)
|
||||
```
|
||||
|
||||
### bintree_is_leaf
|
||||
|
||||
Utility macro that checks if a node has children.
|
||||
|
||||
```c
|
||||
#define bintree_is_leaf(node) ((node)->left == NULL && (node)->right == NULL)
|
||||
```
|
|
@ -24,8 +24,12 @@ void *vec_safe_at(Vector *vec, size_t index);
|
|||
|
||||
void *vec_remove(Vector *vec, size_t index);
|
||||
|
||||
int vec_shrink(Vector *vec);
|
||||
|
||||
#define vec_at(v, i) (v)->elements[(i)]
|
||||
|
||||
#define vec_len(v) (v)->length
|
||||
|
||||
#define vec_cap(v) (v)->capacity
|
||||
|
||||
#endif // LIBFLINT_H_VECTOR
|
||||
|
|
14
src/vector.c
14
src/vector.c
|
@ -95,3 +95,17 @@ void *vec_remove(Vector *vec, size_t index) {
|
|||
vec->length -= 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
int vec_shrink(Vector *vec) {
|
||||
if (vec_len(vec) == vec_cap(vec)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec->capacity = vec_len(vec);
|
||||
vec->elements = reallocf(vec, sizeof(void*) * vec_cap(vec));
|
||||
if (vec->elements == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -236,6 +236,11 @@ void test_vector() {
|
|||
t = (int*)vec_remove(v, 10);
|
||||
assert(t == NULL);
|
||||
|
||||
printf("\ncap before shrink: %zu\n", vec_cap(v));
|
||||
vec_shrink(v);
|
||||
assert(vec_len(v) == vec_cap(v));
|
||||
printf("cap after shrink: %zu\n", vec_cap(v));
|
||||
|
||||
vec_destroy(v);
|
||||
free(v);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue