diff --git a/examples/tree_print.c b/examples/tree_print.c new file mode 100644 index 0000000..1081440 --- /dev/null +++ b/examples/tree_print.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include "../src/treeset.h" + +TREESET_GENERATE(set, set, , , int) + +void print_tree(set_node *root, int height) +{ + if (!root) + return; + + print_tree(root->right, height + 1); + + for (int i = 0; i < height; i++) + printf("|------- "); + + printf("%d\n", root->key); + + print_tree(root->left, height + 1); +} + +int intcmp(int a, int b) +{ + return a - b; +} + +int main(int argc, char const *argv[]) +{ + srand((unsigned)time(NULL)); + set *set1 = set_new(intcmp); + + for (int i = 0; i < 31; i++) + { + set_insert(set1, i); + } + + print_tree(set1->root, 0); + + set_free(set1); + + return 0; +} diff --git a/src/macro_collections.h b/src/macro_collections.h index be2196c..9f65461 100644 --- a/src/macro_collections.h +++ b/src/macro_collections.h @@ -38,6 +38,7 @@ #include "queue.h" #include "deque.h" #include "heap.h" +#include "treeset.h" #include "foreach.h" #endif /* CMC_MACRO_COLLECTIONS */ \ No newline at end of file diff --git a/src/treeset.h b/src/treeset.h new file mode 100644 index 0000000..13ec2f4 --- /dev/null +++ b/src/treeset.h @@ -0,0 +1,694 @@ +/** + * treeset.h + * + * Creation Date: 27/03/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ + +/*****************************************************************************/ +/**************************************************************** TREESET */ +/*****************************************************************************/ + +#ifndef CMC_TREESET_H +#define CMC_TREESET_H + +#include +#include + +#define TREESET_GENERATE(PFX, SNAME, FMOD, K, V) \ + TREESET_GENERATE_STRUCT(PFX, SNAME, FMOD, K, V) \ + TREESET_GENERATE_HEADER(PFX, SNAME, FMOD, K, V) \ + TREESET_GENERATE_SOURCE(PFX, SNAME, FMOD, K, V) + +/* PRIVATE *******************************************************************/ +#define TREESET_GENERATE_HEADER_PRIVATE(PFX, SNAME, FMOD, K, V) \ + TREESET_GENERATE_HEADER(PFX, SNAME, FMOD, K, V) +#define TREESET_GENERATE_SOURCE_PRIVATE(PFX, SNAME, FMOD, K, V) \ + TREESET_GENERATE_STRUCT(PFX, SNAME, FMOD, K, V) \ + TREESET_GENERATE_SOURCE(PFX, SNAME, FMOD, K, V) +/* PUBLIC ********************************************************************/ +#define TREESET_GENERATE_HEADER_PUBLIC(PFX, SNAME, FMOD, K, V) \ + TREESET_GENERATE_STRUCT(PFX, SNAME, FMOD, K, V) \ + TREESET_GENERATE_HEADER(PFX, SNAME, FMOD, K, V) +#define TREESET_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \ + TREESET_GENERATE_SOURCE(PFX, SNAME, FMOD, K, V) +/* STRUCT ********************************************************************/ +#define TREESET_GENERATE_STRUCT(PFX, SNAME, FMOD, K, V) \ + \ + struct SNAME##_s \ + { \ + struct SNAME##_node_s *root; \ + size_t count; \ + int (*cmp)(V, V); \ + }; \ + \ + struct SNAME##_node_s \ + { \ + struct SNAME##_node_s *right; \ + struct SNAME##_node_s *left; \ + struct SNAME##_node_s *parent; \ + unsigned char height; \ + V key; \ + }; \ + \ + struct SNAME##_iter_s \ + { \ + struct SNAME##_s *target; \ + struct SNAME##_node_s *cursor; \ + struct SNAME##_node_s *first; \ + struct SNAME##_node_s *last; \ + size_t index; \ + bool start; \ + bool end; \ + }; \ + \ +/* HEADER ********************************************************************/ +#define TREESET_GENERATE_HEADER(PFX, SNAME, FMOD, K, V) \ + \ + typedef struct SNAME##_s SNAME; \ + typedef struct SNAME##_node_s SNAME##_node; \ + typedef struct SNAME##_iter_s SNAME##_iter; \ + \ + FMOD SNAME *PFX##_new(int (*compare)(V, V)); \ + FMOD void PFX##_free(SNAME *_set_); \ + FMOD bool PFX##_insert(SNAME *_set_, V element); \ + FMOD bool PFX##_remove(SNAME *_set_, V element); \ + FMOD bool PFX##_insert_if(SNAME *_set_, V element, bool condition); \ + FMOD bool PFX##_remove_if(SNAME *_set_, V element, bool condition); \ + FMOD V PFX##_max(SNAME *_set_); \ + FMOD V PFX##_min(SNAME *_set_); \ + FMOD bool PFX##_empty(SNAME *_set_); \ + FMOD size_t PFX##_count(SNAME *_set_); \ + \ + FMOD SNAME *PFX##_union(SNAME *_set1_, SNAME *_set2_); \ + FMOD SNAME *PFX##_intersection(SNAME *_set1_, SNAME *_set2_); \ + FMOD SNAME *PFX##_difference(SNAME *_set1_, SNAME *_set2_); \ + FMOD SNAME *PFX##_symmetric_difference(SNAME *_set1_, SNAME *_set2_); \ + \ + FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \ + FMOD bool PFX##_iter_start(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_end(SNAME##_iter *iter); \ + FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \ + FMOD void PFX##_iter_toend(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index); \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index); \ + \ +/* SOURCE ********************************************************************/ +#define TREESET_GENERATE_SOURCE(PFX, SNAME, FMOD, K, V) \ + \ + FMOD SNAME##_node *PFX##_new_node(V element); \ + FMOD SNAME##_node *PFX##_get_node(SNAME *_set_, V element); \ + FMOD unsigned char PFX##_h(SNAME##_node *node); \ + FMOD unsigned char PFX##_hupdate(SNAME##_node *node); \ + FMOD void PFX##_rotate_right(SNAME##_node **Z); \ + FMOD void PFX##_rotate_left(SNAME##_node **Z); \ + FMOD void PFX##_rebalance(SNAME *_set_, SNAME##_node *node); \ + \ + FMOD SNAME *PFX##_new(int (*compare)(V, V)) \ + { \ + SNAME *_set_ = malloc(sizeof(SNAME)); \ + \ + if (!_set_) \ + return NULL; \ + \ + _set_->count = 0; \ + _set_->root = NULL; \ + _set_->cmp = compare; \ + \ + return _set_; \ + } \ + \ + FMOD void PFX##_free(SNAME *_set_) \ + { \ + SNAME##_node *scan = _set_->root; \ + SNAME##_node *up = NULL; \ + \ + while (scan != NULL) \ + { \ + if (scan->left != NULL) \ + { \ + SNAME##_node *left = scan->left; \ + \ + scan->left = up; \ + up = scan; \ + scan = left; \ + } \ + else if (scan->right != NULL) \ + { \ + SNAME##_node *right = scan->right; \ + \ + scan->left = up; \ + scan->right = NULL; \ + up = scan; \ + scan = right; \ + } \ + else \ + { \ + if (up == NULL) \ + { \ + free(scan); \ + scan = NULL; \ + } \ + \ + while (up != NULL) \ + { \ + free(scan); \ + \ + if (up->right != NULL) \ + { \ + scan = up->right; \ + up->right = NULL; \ + break; \ + } \ + else \ + { \ + scan = up; \ + up = up->left; \ + } \ + } \ + } \ + } \ + \ + free(_set_); \ + } \ + \ + FMOD bool PFX##_insert(SNAME *_set_, V element) \ + { \ + if (PFX##_empty(_set_)) \ + { \ + _set_->root = PFX##_new_node(element); \ + if (!_set_->root) \ + return false; \ + } \ + else \ + { \ + SNAME##_node *scan = _set_->root; \ + SNAME##_node *parent = scan; \ + \ + while (scan != NULL) \ + { \ + parent = scan; \ + \ + if (_set_->cmp(scan->key, element) > 0) \ + scan = scan->left; \ + else if (_set_->cmp(scan->key, element) < 0) \ + scan = scan->right; \ + else \ + return false; \ + } \ + \ + SNAME##_node *node; \ + \ + if (_set_->cmp(parent->key, element) > 0) \ + { \ + parent->left = PFX##_new_node(element); \ + \ + if (!parent->left) \ + return false; \ + \ + parent->left->parent = parent; \ + node = parent->left; \ + } \ + else \ + { \ + parent->right = PFX##_new_node(element); \ + \ + if (!parent->right) \ + return false; \ + \ + parent->right->parent = parent; \ + node = parent->right; \ + } \ + \ + PFX##_rebalance(_set_, node); \ + } \ + \ + _set_->count++; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_remove(SNAME *_set_, V element) \ + { \ + SNAME##_node *node = PFX##_get_node(_set_, element); \ + \ + if (!node) \ + return false; \ + \ + SNAME##_node *temp = NULL, *unbalanced = NULL; \ + \ + bool is_root = node->parent == NULL; \ + \ + if (node->left == NULL && node->right == NULL) \ + { \ + if (is_root) \ + _set_->root = NULL; \ + else \ + { \ + unbalanced = node->parent; \ + \ + if (node->parent->right == node) \ + node->parent->right = NULL; \ + else \ + node->parent->left = NULL; \ + } \ + \ + free(node); \ + } \ + else if (node->left == NULL) \ + { \ + if (is_root) \ + { \ + _set_->root = node->right; \ + _set_->root->parent = NULL; \ + } \ + else \ + { \ + unbalanced = node->parent; \ + \ + node->right->parent = node->parent; \ + \ + if (node->parent->right == node) \ + node->parent->right = node->right; \ + else \ + node->parent->left = node->right; \ + } \ + \ + free(node); \ + } \ + else if (node->right == NULL) \ + { \ + if (is_root) \ + { \ + _set_->root = node->left; \ + _set_->root->parent = NULL; \ + } \ + else \ + { \ + unbalanced = node->parent; \ + \ + node->left->parent = node->parent; \ + \ + if (node->parent->right == node) \ + node->parent->right = node->left; \ + else \ + node->parent->left = node->left; \ + } \ + \ + free(node); \ + } \ + else \ + { \ + temp = node->right; \ + while (temp->left != NULL) \ + temp = temp->left; \ + \ + V temp_key = temp->key; \ + \ + unbalanced = temp->parent; \ + \ + if (temp->left == NULL && temp->right == NULL) \ + { \ + if (temp->parent->right == temp) \ + temp->parent->right = NULL; \ + else \ + temp->parent->left = NULL; \ + } \ + else if (temp->left == NULL) \ + { \ + temp->right->parent = temp->parent; \ + \ + if (temp->parent->right == temp) \ + temp->parent->right = temp->right; \ + else \ + temp->parent->left = temp->right; \ + } \ + else if (temp->right == NULL) \ + { \ + temp->left->parent = temp->parent; \ + \ + if (temp->parent->right == temp) \ + temp->parent->right = temp->left; \ + else \ + temp->parent->left = temp->left; \ + } \ + \ + free(temp); \ + \ + node->key = temp_key; \ + } \ + \ + if (unbalanced != NULL) \ + PFX##_rebalance(_set_, unbalanced); \ + \ + _set_->count--; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_insert_if(SNAME *_set_, V element, bool condition) \ + { \ + if (condition) \ + return PFX##_insert(_set_, element); \ + \ + return false; \ + } \ + \ + FMOD bool PFX##_remove_if(SNAME *_set_, V element, bool condition) \ + { \ + if (condition) \ + return PFX##_remove(_set_, element); \ + \ + return false; \ + } \ + \ + FMOD V PFX##_max(SNAME *_set_) \ + { \ + if (PFX##_empty(_set_)) \ + return 0; \ + \ + SNAME##_node *scan = _set_->root; \ + \ + while (scan->right != NULL) \ + scan = scan->right; \ + \ + return scan->key; \ + } \ + \ + FMOD V PFX##_min(SNAME *_set_) \ + { \ + if (PFX##_empty(_set_)) \ + return 0; \ + \ + SNAME##_node *scan = _set_->root; \ + \ + while (scan->left != NULL) \ + scan = scan->left; \ + \ + return scan->key; \ + } \ + \ + FMOD bool PFX##_empty(SNAME *_set_) \ + { \ + return _set_->count == 0; \ + } \ + \ + FMOD size_t PFX##_count(SNAME *_set_) \ + { \ + return _set_->count; \ + } \ + \ + FMOD SNAME##_node *PFX##_new_node(V element) \ + { \ + SNAME##_node *node = malloc(sizeof(SNAME##_node)); \ + \ + if (!node) \ + return NULL; \ + \ + node->key = element; \ + node->right = NULL; \ + node->left = NULL; \ + node->parent = NULL; \ + node->height = 0; \ + \ + return node; \ + } \ + \ + FMOD SNAME##_node *PFX##_get_node(SNAME *_set_, V element) \ + { \ + if (PFX##_empty(_set_)) \ + return NULL; \ + \ + SNAME##_node *scan = _set_->root; \ + \ + while (scan != NULL) \ + { \ + if (_set_->cmp(scan->key, element) > 0) \ + scan = scan->left; \ + else if (_set_->cmp(scan->key, element) < 0) \ + scan = scan->right; \ + else \ + return scan; \ + } \ + \ + return NULL; \ + } \ + \ + FMOD unsigned char PFX##_h(SNAME##_node *node) \ + { \ + if (node == NULL) \ + return 0; \ + \ + return node->height; \ + } \ + \ + FMOD unsigned char PFX##_hupdate(SNAME##_node *node) \ + { \ + if (node == NULL) \ + return 0; \ + \ + unsigned char h_l = PFX##_h(node->left); \ + unsigned char h_r = PFX##_h(node->right); \ + \ + return 1 + (h_l > h_r ? h_l : h_r); \ + } \ + \ + FMOD void PFX##_rotate_right(SNAME##_node **Z) \ + { \ + SNAME##_node *root = *Z; \ + SNAME##_node *new_root = root->left; \ + \ + if (root->parent != NULL) \ + { \ + if (root->parent->left == root) \ + root->parent->left = new_root; \ + else \ + root->parent->right = new_root; \ + } \ + \ + new_root->parent = root->parent; \ + \ + root->parent = new_root; \ + root->left = new_root->right; \ + \ + if (root->left) \ + root->left->parent = root; \ + \ + new_root->right = root; \ + \ + root->height = PFX##_hupdate(root); \ + new_root->height = PFX##_hupdate(new_root); \ + \ + *Z = new_root; \ + } \ + \ + FMOD void PFX##_rotate_left(SNAME##_node **Z) \ + { \ + SNAME##_node *root = *Z; \ + SNAME##_node *new_root = root->right; \ + \ + if (root->parent != NULL) \ + { \ + if (root->parent->right == root) \ + root->parent->right = new_root; \ + else \ + root->parent->left = new_root; \ + } \ + \ + new_root->parent = root->parent; \ + \ + root->parent = new_root; \ + root->right = new_root->left; \ + \ + if (root->right) \ + root->right->parent = root; \ + \ + new_root->left = root; \ + \ + root->height = PFX##_hupdate(root); \ + new_root->height = PFX##_hupdate(new_root); \ + \ + *Z = new_root; \ + } \ + \ + FMOD void PFX##_rebalance(SNAME *_set_, SNAME##_node *node) \ + { \ + SNAME##_node *scan = node, *child = NULL; \ + \ + int balance; \ + bool is_root = false; \ + \ + while (scan != NULL) \ + { \ + if (scan->parent == NULL) \ + is_root = true; \ + \ + scan->height = PFX##_hupdate(scan); \ + balance = PFX##_h(scan->right) - PFX##_h(scan->left); \ + \ + if (balance >= 2) \ + { \ + child = scan->right; \ + \ + if (PFX##_h(child->right) < PFX##_h(child->left)) \ + PFX##_rotate_right(&(scan->right)); \ + \ + PFX##_rotate_left(&scan); \ + } \ + else if (balance <= -2) \ + { \ + child = scan->left; \ + \ + if (PFX##_h(child->left) < PFX##_h(child->right)) \ + PFX##_rotate_left(&(scan->left)); \ + \ + PFX##_rotate_right(&scan); \ + } \ + \ + if (is_root) \ + { \ + _set_->root = scan; \ + is_root = false; \ + } \ + \ + scan = scan->parent; \ + } \ + } \ + \ + FMOD SNAME *PFX##_union(SNAME *_set1_, SNAME *_set2_); \ + FMOD SNAME *PFX##_intersection(SNAME *_set1_, SNAME *_set2_); \ + FMOD SNAME *PFX##_difference(SNAME *_set1_, SNAME *_set2_); \ + FMOD SNAME *PFX##_symmetric_difference(SNAME *_set1_, SNAME *_set2_); \ + \ + FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target) \ + { \ + iter->target = target; \ + iter->index = 0; \ + iter->start = true; \ + iter->end = PFX##_empty(target); \ + \ + iter->cursor = target->root; \ + while (iter->cursor->left != NULL) \ + iter->cursor = iter->cursor->left; \ + \ + iter->first = iter->cursor; \ + \ + iter->last = target->root; \ + while (iter->last->right != NULL) \ + iter->last = iter->last->right; \ + } \ + \ + FMOD bool PFX##_iter_start(SNAME##_iter *iter) \ + { \ + return iter->start && iter->cursor == iter->first; \ + } \ + \ + FMOD bool PFX##_iter_end(SNAME##_iter *iter) \ + { \ + return iter->end && iter->cursor == iter->last; \ + } \ + \ + FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \ + { \ + iter->index = 0; \ + iter->start = true; \ + iter->end = PFX##_empty(iter->target); \ + \ + iter->cursor = iter->first; \ + } \ + \ + FMOD void PFX##_iter_toend(SNAME##_iter *iter) \ + { \ + iter->index = iter->target->count - 1; \ + iter->start = PFX##_empty(iter->target); \ + iter->end = true; \ + \ + iter->cursor = iter->last; \ + } \ + \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index) \ + { \ + if (iter->end) \ + return false; \ + \ + *result = iter->cursor->key; \ + *index = iter->index; \ + iter->start = false; \ + \ + if (iter->cursor->right != NULL) \ + { \ + iter->cursor = iter->cursor->right; \ + while (iter->cursor->left != NULL) \ + iter->cursor = iter->cursor->left; \ + \ + iter->index++; \ + \ + return true; \ + } \ + \ + while (true) \ + { \ + if (iter->cursor == iter->last) \ + { \ + iter->end = true; \ + \ + return true; \ + } \ + if (iter->cursor->parent->left == iter->cursor) \ + { \ + iter->cursor = iter->cursor->parent; \ + \ + iter->index++; \ + \ + return true; \ + } \ + \ + iter->cursor = iter->cursor->parent; \ + } \ + } \ + \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index) \ + { \ + if (iter->start) \ + return false; \ + \ + *result = iter->cursor->key; \ + *index = iter->index; \ + iter->end = false; \ + \ + if (iter->cursor->left != NULL) \ + { \ + iter->cursor = iter->cursor->left; \ + while (iter->cursor->right != NULL) \ + iter->cursor = iter->cursor->right; \ + \ + iter->index--; \ + \ + return true; \ + } \ + \ + while (true) \ + { \ + if (iter->cursor == iter->first) \ + { \ + iter->start = true; \ + \ + return true; \ + } \ + if (iter->cursor->parent->right == iter->cursor) \ + { \ + iter->cursor = iter->cursor->parent; \ + \ + iter->index--; \ + \ + return true; \ + } \ + \ + iter->cursor = iter->cursor->parent; \ + } \ + } + +#endif /* CMC_TREESET_H */ diff --git a/tests/foreach.c b/tests/foreach.c index 488eed0..fd5de0f 100644 --- a/tests/foreach.c +++ b/tests/foreach.c @@ -13,6 +13,7 @@ CONTAINER_GENERATE(QUEUE, PUBLIC, q, queue, /**/, /**/, int) CONTAINER_GENERATE(DEQUE, PUBLIC, d, deque, /**/, /**/, int) CONTAINER_GENERATE(LINKEDLIST, PUBLIC, ll, linked, /**/, /**/, int) CONTAINER_GENERATE(HEAP, PUBLIC, h, heap, /**/, /**/, int) +CONTAINER_GENERATE(TREESET, PUBLIC, ts, tset, /**/, /**/, int) int main(int argc, char const *argv[]) { @@ -22,6 +23,7 @@ int main(int argc, char const *argv[]) deque *d = d_new(1000); linked *ll = ll_new(); heap *h = h_new(1000, MaxHeap, cmp); + tset *ts = ts_new(cmp); for (int i = 1; i < 10001; i++) { @@ -41,9 +43,10 @@ int main(int argc, char const *argv[]) s_push(s, i); q_enqueue(q, i); h_insert(h, i); + ts_insert(ts, i); } - int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0, sum5 = 0; + int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0, sum5 = 0, sum6 = 0; FOR_EACH(l, list, , int, l, { sum0 += var; @@ -69,6 +72,10 @@ int main(int argc, char const *argv[]) sum5 += var; }) + FOR_EACH(ts, tset, , int, ts, { + sum6 += var; + }) + if (sum0 == 50005000) printf("%10s PASSED\n", "LIST"); if (sum1 == 50005000) @@ -81,10 +88,12 @@ int main(int argc, char const *argv[]) printf("%10s PASSED\n", "LINKEDLIST"); if (sum5 == 50005000) printf("%10s PASSED\n", "HEAP"); + if (sum6 == 50005000) + printf("%10s PASSED\n", "TREESET"); printf("\n\n"); - sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0, sum5 = 0; + sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0, sum5 = 0, sum6 = 0; FOR_EACH_REV(l, list, , int, l, { sum0 += var; @@ -110,6 +119,10 @@ int main(int argc, char const *argv[]) sum5 += var; }) + FOR_EACH_REV(ts, tset, , int, ts, { + sum6 += var; + }) + if (sum0 == 50005000) printf("%10s PASSED\n", "LIST"); if (sum1 == 50005000) @@ -122,6 +135,8 @@ int main(int argc, char const *argv[]) printf("%10s PASSED\n", "LINKEDLIST"); if (sum5 == 50005000) printf("%10s PASSED\n", "HEAP"); + if (sum6 == 50005000) + printf("%10s PASSED\n", "TREESET"); l_free(l); ll_free(ll); diff --git a/tests/iterators/treeset.c b/tests/iterators/treeset.c new file mode 100644 index 0000000..226cba7 --- /dev/null +++ b/tests/iterators/treeset.c @@ -0,0 +1,58 @@ +// Checks if the treeset iterator can go back and forward in the treeset without +// hitting invalid states or a null pointer. Check is done visually. +#include +#include +#include +#include +#include "../../src/treeset.h" + +int intcmp(int a, int b) +{ + return a - b; +} + +TREESET_GENERATE(ts, tset, static, , int) + +int main(int argc, char const *argv[]) +{ + size_t i; + int r; + + // Initliazie treeset and add some elements + tset *ts = ts_new(intcmp); + for (int i = 0; i < 10; i++) + ts_insert(ts, i); + + // Initialize iterator + tset_iter iter; + ts_iter_new(&iter, ts); + + // Make the iterator go back and forward + for (int j = 0; j < 4; j++) + { + while (ts_iter_next(&iter, &r, &i)) + printf("C[%2d] = %2d\n", i, r); + printf("\n"); + while (ts_iter_prev(&iter, &r, &i)) + printf("C[%2d] = %2d\n", i, r); + printf("\n\n"); + } + + for (ts_iter_tostart(&iter); !ts_iter_end(&iter); /**/) + { + ts_iter_next(&iter, &r, &i); + printf("S[%2d] = %2d\n", i, r); + } + + printf("\n"); + + for (ts_iter_toend(&iter); !ts_iter_start(&iter); /**/) + { + ts_iter_prev(&iter, &r, &i); + printf("S[%2d] = %2d\n", i, r); + } + + ts_free(ts); + + return 0; +}