Complete remake of multiset
This commit is contained in:
1 parent
90ee6a424d
commit
1254e657c5
7 files changed
+1895
-859
No files matched your search
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* multiset_operations.c
|
||||
*
|
||||
* Creation Date: 01/08/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include <ext/multiset.h>
|
||||
#include <utl/assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
MULTISET_GENERATE(ms, multiset, , char)
|
||||
|
||||
struct pair
|
||||
{
|
||||
char value;
|
||||
size_t mul;
|
||||
};
|
||||
|
||||
int charcmp(char a, char b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
size_t charhash(char a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
void print_set(multiset *M)
|
||||
{
|
||||
cmc_assert_not_equals(ptr, NULL, M);
|
||||
|
||||
size_t S = ms_count(M);
|
||||
|
||||
printf("%s : ", ms_to_string(M).s);
|
||||
|
||||
if (S == 0)
|
||||
{
|
||||
printf("{ EMPTY SET }\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (multiset_iter it = M->it_start(M); !ms_iter_end(&it); ms_iter_next(&it))
|
||||
{
|
||||
size_t index = ms_iter_index(&it);
|
||||
char value = ms_iter_value(&it);
|
||||
size_t mul = ms_iter_multiplicity(&it);
|
||||
|
||||
if (index == 0)
|
||||
printf("{ %c:%" PRIuMAX ", ", value, mul);
|
||||
else if (index == S - 1)
|
||||
printf("%c:%" PRIuMAX " }\n", value, mul);
|
||||
else
|
||||
printf("%c:%" PRIuMAX ", ", value, mul);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
struct pair mset1[4] = {{'a', 2}, {'b', 1}, {'c', 3}, {'d', 1}};
|
||||
struct pair mset2[4] = {{'c', 1}, {'d', 3}, {'e', 1}, {'f', 2}};
|
||||
|
||||
multiset *A = ms_new(20, 0.6, charcmp, charhash);
|
||||
multiset *B = ms_new(20, 0.6, charcmp, charhash);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
cmc_assert(ms_insert_many(A, mset1[i].value, mset1[i].mul));
|
||||
cmc_assert(ms_insert_many(B, mset2[i].value, mset2[i].mul));
|
||||
}
|
||||
|
||||
printf("Given two sets A and B:\n");
|
||||
print_set(A);
|
||||
print_set(B);
|
||||
|
||||
multiset *U = ms_union(A, B);
|
||||
printf("\nA UNION B:\n");
|
||||
print_set(U);
|
||||
|
||||
multiset *I = ms_intersection(A, B);
|
||||
printf("\nA INTERSECTION B:\n");
|
||||
print_set(I);
|
||||
|
||||
multiset *DA = ms_difference(A, B);
|
||||
multiset *DB = ms_difference(B, A);
|
||||
printf("\nA - B:\n");
|
||||
print_set(DA);
|
||||
printf("\nB - A:\n");
|
||||
print_set(DB);
|
||||
|
||||
multiset *AB = ms_summation(A, B);
|
||||
printf("\nA + B:\n");
|
||||
print_set(AB);
|
||||
|
||||
multiset *BA = ms_summation(B, A);
|
||||
printf("\nB + A:\n");
|
||||
print_set(BA);
|
||||
|
||||
multiset *SD = ms_symmetric_difference(A, B);
|
||||
printf("\nA SYM DIFF B:\n");
|
||||
print_set(SD);
|
||||
|
||||
ms_free(A);
|
||||
ms_free(B);
|
||||
ms_free(U);
|
||||
ms_free(I);
|
||||
ms_free(DA);
|
||||
ms_free(DB);
|
||||
ms_free(AB);
|
||||
ms_free(BA);
|
||||
ms_free(SD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "multiset.h"
|
||||
|
||||
MULTISET_GENERATE(ms, multi_set, /* FMOD */, size_t)
|
||||
|
||||
int cmp(size_t a, size_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return 1;
|
||||
else if (a < b)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void prime_cof(const size_t number)
|
||||
{
|
||||
multi_set *mset = ms_new(cmp);
|
||||
|
||||
size_t num = number;
|
||||
|
||||
for (size_t i = 2; num != 1; i++)
|
||||
{
|
||||
while (num % i == 0)
|
||||
{
|
||||
ms_insert(mset, i);
|
||||
num /= i;
|
||||
}
|
||||
}
|
||||
|
||||
printf("The factorization of %llu is given by:\n", number);
|
||||
|
||||
multi_set_iter iter;
|
||||
size_t result, mul, index;
|
||||
for (ms_iter_new(&iter, mset); !ms_iter_end(&iter);)
|
||||
{
|
||||
if (!ms_iter_next(&iter, &result, &mul, &index))
|
||||
{
|
||||
printf("ERROR\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (ms_count(mset) == 1)
|
||||
printf("(%llu^%llu)\n", result, mul);
|
||||
else if (index == 0)
|
||||
printf("(%llu^%llu ", result, mul);
|
||||
else if (index == ms_count(mset) - 1)
|
||||
printf("* %llu^%llu)\n", result, mul);
|
||||
else
|
||||
printf("* %llu^%llu ", result, mul);
|
||||
}
|
||||
|
||||
printf("Set Cardinality: %llu\n\n", ms_cardinality(mset));
|
||||
|
||||
ms_free(mset);
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
prime_cof(360);
|
||||
prime_cof(55777680);
|
||||
prime_cof(4294967296);
|
||||
prime_cof(31415926535);
|
||||
prime_cof(27182818284);
|
||||
prime_cof(16180339887);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+1012
-789
File diff suppressed because it is too large.
Load diff
@@ -23,7 +23,7 @@ typedef struct cmc_string_s
|
||||
char s[200];
|
||||
} cmc_string;
|
||||
|
||||
/* To string formatting */
|
||||
/* to_string formats */
|
||||
static const char *cmc_string_fmt_deque = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
|
||||
static const char *cmc_string_fmt_hashmap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
||||
static const char *cmc_string_fmt_hashset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
||||
@@ -32,7 +32,9 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
||||
static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
|
||||
static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
||||
static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p, }";
|
||||
static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p, }";
|
||||
static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
||||
static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
||||
|
||||
static const char *cmc_string_fmt_multiset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", cardinality:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";;
|
||||
|
||||
#endif /* CMC_STRING_H */
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "unt/linkedqueue.c"
|
||||
#include "unt/multimap.c"
|
||||
#include "unt/multiset.c"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -28,6 +29,7 @@ int main(void)
|
||||
/* ext */
|
||||
linkedqueue_test();
|
||||
multimap_test();
|
||||
multiset_test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,655 @@
|
||||
#include "ext/multiset.h"
|
||||
|
||||
//MULTISET_GENERATE(ms, multiset, , size_t)
|
||||
|
||||
typedef struct multiset_s
|
||||
{
|
||||
struct multiset_entry_s *buffer;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
size_t cardinality;
|
||||
double load;
|
||||
int (*cmp)(size_t, size_t);
|
||||
size_t (*hash)(size_t);
|
||||
struct multiset_iter_s (*it_start)(struct multiset_s *);
|
||||
struct multiset_iter_s (*it_end)(struct multiset_s *);
|
||||
} multiset, *multiset_ptr;
|
||||
typedef struct multiset_entry_s
|
||||
{
|
||||
size_t value;
|
||||
size_t multiplicity;
|
||||
size_t dist;
|
||||
enum cmc_entry_state_e state;
|
||||
} multiset_entry, *multiset_entry_ptr;
|
||||
typedef struct multiset_iter_s
|
||||
{
|
||||
struct multiset_s *target;
|
||||
size_t cursor;
|
||||
size_t index;
|
||||
size_t first;
|
||||
size_t last;
|
||||
bool start;
|
||||
bool end;
|
||||
} multiset_iter, *multiset_iter_ptr;
|
||||
multiset *ms_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t));
|
||||
void ms_clear(multiset *_set_);
|
||||
void ms_free(multiset *_set_);
|
||||
bool ms_insert(multiset *_set_, size_t element);
|
||||
bool ms_insert_many(multiset *_set_, size_t element, size_t count);
|
||||
bool ms_update(multiset *_set_, size_t element, size_t multiplicity);
|
||||
bool ms_remove(multiset *_set_, size_t element);
|
||||
size_t ms_remove_all(multiset *_set_, size_t element);
|
||||
bool ms_insert_if(multiset *_set_, size_t element, bool condition);
|
||||
bool ms_remove_if(multiset *_set_, size_t element, bool condition);
|
||||
bool ms_max(multiset *_set_, size_t *value);
|
||||
bool ms_min(multiset *_set_, size_t *value);
|
||||
size_t ms_multiplicity_of(multiset *_set_, size_t element);
|
||||
bool ms_contains(multiset *_set_, size_t element);
|
||||
bool ms_empty(multiset *_set_);
|
||||
size_t ms_count(multiset *_set_);
|
||||
size_t ms_cardinality(multiset *_set_);
|
||||
size_t ms_capacity(multiset *_set_);
|
||||
cmc_string ms_to_string(multiset *_set_);
|
||||
multiset *ms_union(multiset *_set1_, multiset *_set2_);
|
||||
multiset *ms_intersection(multiset *_set1_, multiset *_set2_);
|
||||
multiset *ms_difference(multiset *_set1_, multiset *_set2_);
|
||||
multiset *ms_summation(multiset *_set1_, multiset *_set2_);
|
||||
multiset *ms_symmetric_difference(multiset *_set1_, multiset *_set2_);
|
||||
bool ms_is_subset(multiset *_set1_, multiset *_set2_);
|
||||
bool ms_is_superset(multiset *_set1_, multiset *_set2_);
|
||||
bool ms_is_proper_subset(multiset *_set1_, multiset *_set2_);
|
||||
bool ms_is_proper_superset(multiset *_set1_, multiset *_set2_);
|
||||
bool ms_is_disjointset(multiset *_set1_, multiset *_set2_);
|
||||
multiset_iter *ms_iter_new(multiset *target);
|
||||
void ms_iter_free(multiset_iter *iter);
|
||||
void ms_iter_init(multiset_iter *iter, multiset *target);
|
||||
bool ms_iter_start(multiset_iter *iter);
|
||||
bool ms_iter_end(multiset_iter *iter);
|
||||
void ms_iter_to_start(multiset_iter *iter);
|
||||
void ms_iter_to_end(multiset_iter *iter);
|
||||
bool ms_iter_next(multiset_iter *iter);
|
||||
bool ms_iter_prev(multiset_iter *iter);
|
||||
size_t ms_iter_value(multiset_iter *iter);
|
||||
size_t ms_iter_multiplicity(multiset_iter *iter);
|
||||
size_t ms_iter_index(multiset_iter *iter);
|
||||
static inline size_t ms_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
static multiset_entry *ms_impl_insert_and_return(multiset *_set_, size_t element, bool *new_node);
|
||||
static bool ms_impl_grow(multiset *_set_);
|
||||
static multiset_entry *ms_impl_get_entry(multiset *_set_, size_t element);
|
||||
static size_t ms_impl_calculate_size(size_t required);
|
||||
static multiset_iter ms_impl_it_start(multiset *_set_);
|
||||
static multiset_iter ms_impl_it_end(multiset *_set_);
|
||||
multiset *ms_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t))
|
||||
{
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return NULL;
|
||||
if (capacity >= UINTMAX_MAX * load)
|
||||
return NULL;
|
||||
size_t real_capacity = ms_impl_calculate_size(capacity / load);
|
||||
multiset *_set_ = malloc(sizeof(multiset));
|
||||
if (!_set_)
|
||||
return NULL;
|
||||
_set_->buffer = malloc(sizeof(multiset_entry) * real_capacity);
|
||||
if (!_set_->buffer)
|
||||
{
|
||||
free(_set_);
|
||||
return NULL;
|
||||
}
|
||||
memset(_set_->buffer, 0, sizeof(multiset_entry) * real_capacity);
|
||||
_set_->count = 0;
|
||||
_set_->cardinality = 0;
|
||||
_set_->capacity = real_capacity;
|
||||
_set_->load = load;
|
||||
_set_->cmp = compare;
|
||||
_set_->hash = hash;
|
||||
_set_->it_start = ms_impl_it_start;
|
||||
_set_->it_end = ms_impl_it_end;
|
||||
return _set_;
|
||||
}
|
||||
void ms_clear(multiset *_set_)
|
||||
{
|
||||
memset(_set_->buffer, 0, sizeof(multiset_entry) * _set_->capacity);
|
||||
_set_->count = 0;
|
||||
}
|
||||
void ms_free(multiset *_set_)
|
||||
{
|
||||
free(_set_->buffer);
|
||||
free(_set_);
|
||||
}
|
||||
bool ms_insert(multiset *_set_, size_t element)
|
||||
{
|
||||
bool new_node;
|
||||
multiset_entry *entry = ms_impl_insert_and_return(_set_, element, &new_node);
|
||||
if (!entry)
|
||||
return false;
|
||||
if (!new_node)
|
||||
entry->multiplicity++;
|
||||
_set_->cardinality++;
|
||||
return true;
|
||||
}
|
||||
bool ms_insert_many(multiset *_set_, size_t element, size_t count)
|
||||
{
|
||||
if (count == 0)
|
||||
return true;
|
||||
bool new_node;
|
||||
multiset_entry *entry = ms_impl_insert_and_return(_set_, element, &new_node);
|
||||
if (!entry)
|
||||
return false;
|
||||
if (new_node)
|
||||
entry->multiplicity = count;
|
||||
else
|
||||
entry->multiplicity += count;
|
||||
_set_->cardinality += count;
|
||||
return true;
|
||||
}
|
||||
bool ms_update(multiset *_set_, size_t element, size_t multiplicity)
|
||||
{
|
||||
if (multiplicity == 0)
|
||||
return ms_remove_all(_set_, element);
|
||||
bool new_node;
|
||||
multiset_entry *entry = ms_impl_insert_and_return(_set_, element, &new_node);
|
||||
if (!entry)
|
||||
return false;
|
||||
if (new_node)
|
||||
_set_->cardinality++;
|
||||
_set_->cardinality = (_set_->cardinality - entry->multiplicity) + multiplicity;
|
||||
entry->multiplicity = multiplicity;
|
||||
return true;
|
||||
}
|
||||
bool ms_remove(multiset *_set_, size_t element)
|
||||
{
|
||||
multiset_entry *result = ms_impl_get_entry(_set_, element);
|
||||
if (result == NULL)
|
||||
return false;
|
||||
if (result->multiplicity > 1)
|
||||
result->multiplicity--;
|
||||
else
|
||||
{
|
||||
result->value = ms_impl_default_value();
|
||||
result->multiplicity = 0;
|
||||
result->dist = 0;
|
||||
result->state = CMC_ES_DELETED;
|
||||
_set_->count--;
|
||||
}
|
||||
_set_->cardinality--;
|
||||
return true;
|
||||
}
|
||||
size_t ms_remove_all(multiset *_set_, size_t element)
|
||||
{
|
||||
multiset_entry *result = ms_impl_get_entry(_set_, element);
|
||||
if (result == NULL)
|
||||
return 0;
|
||||
size_t removed = result->multiplicity;
|
||||
result->value = ms_impl_default_value();
|
||||
result->multiplicity = 0;
|
||||
result->dist = 0;
|
||||
result->state = CMC_ES_DELETED;
|
||||
_set_->count--;
|
||||
_set_->cardinality -= removed;
|
||||
return removed;
|
||||
}
|
||||
bool ms_insert_if(multiset *_set_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return ms_insert(_set_, element);
|
||||
return false;
|
||||
}
|
||||
bool ms_remove_if(multiset *_set_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return ms_remove(_set_, element);
|
||||
return false;
|
||||
}
|
||||
bool ms_max(multiset *_set_, size_t *value)
|
||||
{
|
||||
if (ms_empty(_set_))
|
||||
return false;
|
||||
multiset_iter iter;
|
||||
for (ms_iter_init(&iter, _set_); !ms_iter_end(&iter); ms_iter_next(&iter))
|
||||
{
|
||||
size_t result = ms_iter_value(&iter);
|
||||
size_t index = ms_iter_index(&iter);
|
||||
if (index == 0)
|
||||
*value = result;
|
||||
else if (_set_->cmp(result, *value) > 0)
|
||||
*value = result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool ms_min(multiset *_set_, size_t *value)
|
||||
{
|
||||
if (ms_empty(_set_))
|
||||
return false;
|
||||
multiset_iter iter;
|
||||
for (ms_iter_init(&iter, _set_); !ms_iter_end(&iter); ms_iter_next(&iter))
|
||||
{
|
||||
size_t result = ms_iter_value(&iter);
|
||||
size_t index = ms_iter_index(&iter);
|
||||
if (index == 0)
|
||||
*value = result;
|
||||
else if (_set_->cmp(result, *value) < 0)
|
||||
*value = result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
size_t ms_multiplicity_of(multiset *_set_, size_t element)
|
||||
{
|
||||
multiset_entry *entry = ms_impl_get_entry(_set_, element);
|
||||
if (!entry)
|
||||
return 0;
|
||||
return entry->multiplicity;
|
||||
}
|
||||
bool ms_contains(multiset *_set_, size_t element) { return ms_impl_get_entry(_set_, element) != NULL; }
|
||||
bool ms_empty(multiset *_set_) { return _set_->count == 0; }
|
||||
size_t ms_count(multiset *_set_) { return _set_->count; }
|
||||
size_t ms_cardinality(multiset *_set_) { return _set_->cardinality; }
|
||||
size_t ms_capacity(multiset *_set_) { return _set_->capacity; }
|
||||
cmc_string ms_to_string(multiset *_set_)
|
||||
{
|
||||
cmc_string str;
|
||||
multiset *s_ = _set_;
|
||||
const char *name = "multiset";
|
||||
snprintf(str.s, cmc_string_len, cmc_string_fmt_multiset, name, s_, s_->buffer, s_->capacity, s_->count, s_->cardinality, s_->load, s_->cmp, s_->hash);
|
||||
return str;
|
||||
}
|
||||
multiset *ms_union(multiset *_set1_, multiset *_set2_)
|
||||
{
|
||||
multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
|
||||
if (!_set_r_)
|
||||
return NULL;
|
||||
multiset_iter iter1, iter2;
|
||||
ms_iter_init(&iter1, _set1_);
|
||||
ms_iter_init(&iter2, _set2_);
|
||||
for (ms_iter_to_start(&iter1); !ms_iter_end(&iter1); ms_iter_next(&iter1))
|
||||
{
|
||||
size_t value = ms_iter_value(&iter1);
|
||||
size_t m1 = ms_iter_multiplicity(&iter1);
|
||||
size_t m2 = ms_multiplicity_of(_set2_, value);
|
||||
size_t max_ = m1 > m2 ? m1 : m2;
|
||||
ms_update(_set_r_, value, max_);
|
||||
}
|
||||
for (ms_iter_to_start(&iter2); !ms_iter_end(&iter2); ms_iter_next(&iter2))
|
||||
{
|
||||
size_t value = ms_iter_value(&iter2);
|
||||
size_t m1 = ms_multiplicity_of(_set1_, value);
|
||||
size_t m2 = ms_iter_multiplicity(&iter2);
|
||||
size_t max_ = m1 > m2 ? m1 : m2;
|
||||
ms_update(_set_r_, value, max_);
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
multiset *ms_intersection(multiset *_set1_, multiset *_set2_)
|
||||
{
|
||||
multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
|
||||
if (!_set_r_)
|
||||
return NULL;
|
||||
multiset *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_;
|
||||
multiset *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_;
|
||||
multiset_iter iter;
|
||||
ms_iter_init(&iter, _set_A_);
|
||||
for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter))
|
||||
{
|
||||
size_t value = ms_iter_value(&iter);
|
||||
size_t m1 = ms_iter_multiplicity(&iter);
|
||||
size_t m2 = ms_multiplicity_of(_set_B_, value);
|
||||
size_t max_ = m1 < m2 ? m1 : m2;
|
||||
ms_update(_set_r_, value, max_);
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
multiset *ms_difference(multiset *_set1_, multiset *_set2_)
|
||||
{
|
||||
multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
|
||||
if (!_set_r_)
|
||||
return NULL;
|
||||
multiset_iter iter;
|
||||
ms_iter_init(&iter, _set1_);
|
||||
for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter))
|
||||
{
|
||||
size_t value = ms_iter_value(&iter);
|
||||
size_t m1 = ms_iter_multiplicity(&iter);
|
||||
size_t m2 = ms_multiplicity_of(_set2_, value);
|
||||
if (m1 > m2)
|
||||
ms_update(_set_r_, value, m1 - m2);
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
multiset *ms_summation(multiset *_set1_, multiset *_set2_)
|
||||
{
|
||||
multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
|
||||
if (!_set_r_)
|
||||
return NULL;
|
||||
multiset_iter iter1, iter2;
|
||||
ms_iter_init(&iter1, _set1_);
|
||||
ms_iter_init(&iter2, _set2_);
|
||||
for (ms_iter_to_start(&iter1); !ms_iter_end(&iter1); ms_iter_next(&iter1))
|
||||
{
|
||||
ms_insert_many(_set_r_, ms_iter_value(&iter1), ms_iter_multiplicity(&iter1));
|
||||
}
|
||||
for (ms_iter_to_start(&iter2); !ms_iter_end(&iter2); ms_iter_next(&iter2))
|
||||
{
|
||||
ms_insert_many(_set_r_, ms_iter_value(&iter2), ms_iter_multiplicity(&iter2));
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
multiset *ms_symmetric_difference(multiset *_set1_, multiset *_set2_)
|
||||
{
|
||||
multiset_iter iter1, iter2;
|
||||
multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
|
||||
if (!_set_r_)
|
||||
return NULL;
|
||||
ms_iter_init(&iter1, _set1_);
|
||||
ms_iter_init(&iter2, _set2_);
|
||||
for (ms_iter_to_start(&iter1); !ms_iter_end(&iter1); ms_iter_next(&iter1))
|
||||
{
|
||||
size_t value = ms_iter_value(&iter1);
|
||||
size_t m1 = ms_iter_multiplicity(&iter1);
|
||||
size_t m2 = ms_multiplicity_of(_set2_, value);
|
||||
if (m1 != m2)
|
||||
{
|
||||
if (m1 > m2)
|
||||
ms_update(_set_r_, value, m1 - m2);
|
||||
else
|
||||
ms_update(_set_r_, value, m2 - m1);
|
||||
}
|
||||
}
|
||||
for (ms_iter_to_start(&iter2); !ms_iter_end(&iter2); ms_iter_next(&iter2))
|
||||
{
|
||||
size_t value = ms_iter_value(&iter2);
|
||||
size_t m1 = ms_multiplicity_of(_set1_, value);
|
||||
size_t m2 = ms_iter_multiplicity(&iter2);
|
||||
if (m1 != m2)
|
||||
{
|
||||
if (m1 > m2)
|
||||
ms_update(_set_r_, value, m1 - m2);
|
||||
else
|
||||
ms_update(_set_r_, value, m2 - m1);
|
||||
}
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
bool ms_is_subset(multiset *_set1_, multiset *_set2_)
|
||||
{
|
||||
if (ms_count(_set1_) > ms_count(_set2_))
|
||||
return false;
|
||||
if (ms_empty(_set1_))
|
||||
return true;
|
||||
multiset_iter iter;
|
||||
ms_iter_init(&iter, _set1_);
|
||||
for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter))
|
||||
{
|
||||
size_t value = ms_iter_value(&iter);
|
||||
size_t m1 = ms_iter_multiplicity(&iter);
|
||||
size_t m2 = ms_multiplicity_of(_set2_, value);
|
||||
if (m1 > m2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool ms_is_superset(multiset *_set1_, multiset *_set2_) { return ms_is_subset(_set2_, _set1_); }
|
||||
bool ms_is_proper_subset(multiset *_set1_, multiset *_set2_)
|
||||
{
|
||||
if (ms_count(_set1_) >= ms_count(_set2_))
|
||||
return false;
|
||||
if (ms_empty(_set1_))
|
||||
{
|
||||
if (!ms_empty(_set2_))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
multiset_iter iter;
|
||||
ms_iter_init(&iter, _set1_);
|
||||
for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter))
|
||||
{
|
||||
size_t value = ms_iter_value(&iter);
|
||||
size_t m1 = ms_iter_multiplicity(&iter);
|
||||
size_t m2 = ms_multiplicity_of(_set2_, value);
|
||||
if (m1 >= m2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool ms_is_proper_superset(multiset *_set1_, multiset *_set2_) { return ms_is_proper_subset(_set2_, _set1_); }
|
||||
bool ms_is_disjointset(multiset *_set1_, multiset *_set2_)
|
||||
{
|
||||
if (ms_empty(_set1_))
|
||||
return true;
|
||||
multiset_iter iter;
|
||||
ms_iter_init(&iter, _set1_);
|
||||
for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter))
|
||||
{
|
||||
size_t value = ms_iter_value(&iter);
|
||||
if (ms_contains(_set2_, value))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
multiset_iter *ms_iter_new(multiset *target)
|
||||
{
|
||||
multiset_iter *iter = malloc(sizeof(multiset_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
ms_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void ms_iter_free(multiset_iter *iter) { free(iter); }
|
||||
void ms_iter_init(multiset_iter *iter, multiset *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = 0;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = ms_empty(target);
|
||||
if (!ms_empty(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
if (target->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter->first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter->cursor = iter->first;
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
if (target->buffer[i - 1].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter->last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bool ms_iter_start(multiset_iter *iter) { return ms_empty(iter->target) || iter->start; }
|
||||
bool ms_iter_end(multiset_iter *iter) { return ms_empty(iter->target) || iter->end; }
|
||||
void ms_iter_to_start(multiset_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->first;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = ms_empty(iter->target);
|
||||
}
|
||||
void ms_iter_to_end(multiset_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->last;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = ms_empty(iter->target);
|
||||
iter->end = true;
|
||||
}
|
||||
bool ms_iter_next(multiset_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
multiset_entry *scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (iter->cursor == iter->last)
|
||||
iter->end = true;
|
||||
else
|
||||
{
|
||||
iter->index++;
|
||||
while (1)
|
||||
{
|
||||
iter->cursor++;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (scan->state == CMC_ES_FILLED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter->start = ms_empty(iter->target);
|
||||
return true;
|
||||
}
|
||||
bool ms_iter_prev(multiset_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
multiset_entry *scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (iter->cursor == iter->first)
|
||||
iter->start = true;
|
||||
else
|
||||
{
|
||||
iter->index--;
|
||||
while (1)
|
||||
{
|
||||
iter->cursor--;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (scan->state == CMC_ES_FILLED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter->end = ms_empty(iter->target);
|
||||
return true;
|
||||
}
|
||||
size_t ms_iter_value(multiset_iter *iter)
|
||||
{
|
||||
if (ms_empty(iter->target))
|
||||
return ms_impl_default_value();
|
||||
return iter->target->buffer[iter->cursor].value;
|
||||
}
|
||||
size_t ms_iter_multiplicity(multiset_iter *iter)
|
||||
{
|
||||
if (ms_empty(iter->target))
|
||||
return 0;
|
||||
return iter->target->buffer[iter->cursor].multiplicity;
|
||||
}
|
||||
size_t ms_iter_index(multiset_iter *iter) { return iter->index; }
|
||||
static multiset_entry *ms_impl_insert_and_return(multiset *_set_, size_t element, bool *new_node)
|
||||
{
|
||||
*new_node = false;
|
||||
multiset_entry *entry = ms_impl_get_entry(_set_, element);
|
||||
if (entry != NULL)
|
||||
return entry;
|
||||
*new_node = true;
|
||||
if ((double)_set_->capacity * _set_->load <= (double)_set_->count)
|
||||
{
|
||||
if (!ms_impl_grow(_set_))
|
||||
return NULL;
|
||||
}
|
||||
size_t hash = _set_->hash(element);
|
||||
size_t original_pos = hash % _set_->capacity;
|
||||
size_t pos = original_pos;
|
||||
size_t curr_mul = 1;
|
||||
multiset_entry *target = &(_set_->buffer[pos]);
|
||||
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
target->value = element;
|
||||
target->multiplicity = curr_mul;
|
||||
target->dist = pos - original_pos;
|
||||
target->state = CMC_ES_FILLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pos++;
|
||||
target = &(_set_->buffer[pos % _set_->capacity]);
|
||||
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
target->value = element;
|
||||
target->multiplicity = curr_mul;
|
||||
target->dist = pos - original_pos;
|
||||
target->state = CMC_ES_FILLED;
|
||||
break;
|
||||
}
|
||||
else if (target->dist < pos - original_pos)
|
||||
{
|
||||
size_t tmp = target->value;
|
||||
size_t tmp_dist = target->dist;
|
||||
size_t tmp_mul = target->multiplicity;
|
||||
target->value = element;
|
||||
target->dist = pos - original_pos;
|
||||
target->multiplicity = curr_mul;
|
||||
element = tmp;
|
||||
original_pos = pos - tmp_dist;
|
||||
curr_mul = tmp_mul;
|
||||
}
|
||||
}
|
||||
}
|
||||
_set_->count++;
|
||||
return target;
|
||||
}
|
||||
static bool ms_impl_grow(multiset *_set_)
|
||||
{
|
||||
size_t new_size = ms_impl_calculate_size(_set_->capacity + _set_->capacity / 2);
|
||||
multiset *_new_set_ = ms_new(new_size, _set_->load, _set_->cmp, _set_->hash);
|
||||
if (!_new_set_)
|
||||
return false;
|
||||
multiset_iter iter;
|
||||
for (ms_iter_init(&iter, _set_); !ms_iter_end(&iter); ms_iter_next(&iter))
|
||||
{
|
||||
ms_insert_many(_new_set_, ms_iter_value(&iter), ms_iter_multiplicity(&iter));
|
||||
}
|
||||
if (_set_->count != _new_set_->count)
|
||||
{
|
||||
ms_free(_new_set_);
|
||||
return false;
|
||||
}
|
||||
multiset_entry *tmp = _set_->buffer;
|
||||
_set_->buffer = _new_set_->buffer;
|
||||
_new_set_->buffer = tmp;
|
||||
_set_->capacity = _new_set_->capacity;
|
||||
ms_free(_new_set_);
|
||||
return true;
|
||||
}
|
||||
static multiset_entry *ms_impl_get_entry(multiset *_set_, size_t element)
|
||||
{
|
||||
size_t hash = _set_->hash(element);
|
||||
size_t pos = hash % _set_->capacity;
|
||||
multiset_entry *target = &(_set_->buffer[pos]);
|
||||
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
if (_set_->cmp(target->value, element) == 0)
|
||||
return target;
|
||||
pos++;
|
||||
target = &(_set_->buffer[pos % _set_->capacity]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static size_t ms_impl_calculate_size(size_t required)
|
||||
{
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
|
||||
if (cmc_hashtable_primes[count - 1] < required)
|
||||
return required;
|
||||
size_t i = 0;
|
||||
while (cmc_hashtable_primes[i] < required)
|
||||
i++;
|
||||
return cmc_hashtable_primes[i];
|
||||
}
|
||||
static multiset_iter ms_impl_it_start(multiset *_set_)
|
||||
{
|
||||
multiset_iter iter;
|
||||
ms_iter_init(&iter, _set_);
|
||||
return iter;
|
||||
}
|
||||
static multiset_iter ms_impl_it_end(multiset *_set_)
|
||||
{
|
||||
multiset_iter iter;
|
||||
ms_iter_init(&iter, _set_);
|
||||
ms_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/multiset.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(multiset_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
multiset *set = ms_new(943722, 0.6, cmp, hash);
|
||||
|
||||
bool passed = (set->capacity >= (943722 / 0.6)) && set->count == 0 && set->buffer;
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
cmc_assert(ms_capacity(set) > (943722 / 0.6));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
ms_free(set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
multiset *set = ms_new(0, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(set == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINTMAX_MAX], {
|
||||
multiset *set = ms_new(UINTMAX_MAX, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(set == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
multiset *set = ms_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(ms_insert(set, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, ms_count(set));
|
||||
|
||||
ms_clear(set);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ms_count(set));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(ms_count(set) == 0);
|
||||
|
||||
ms_free(set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[count cardinality multiplicity], {
|
||||
multiset *set = ms_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert(ms_insert(set, 1));
|
||||
cmc_assert(ms_insert(set, 2));
|
||||
cmc_assert(ms_insert(set, 2));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
|
||||
cmc_assert_equals(size_t, 3, ms_count(set));
|
||||
cmc_assert_equals(size_t, 6, ms_cardinality(set));
|
||||
|
||||
bool passed = ms_count(set) == 3 && ms_cardinality(set) == 6;
|
||||
|
||||
for (size_t i = 0; i <= 3; i++)
|
||||
passed = passed && ms_multiplicity_of(set, i) == i;
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
ms_free(set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(multiplicity, {
|
||||
multiset *set = ms_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(ms_insert(set, i % 20));
|
||||
|
||||
cmc_assert_equals(size_t, 20, ms_count(set));
|
||||
cmc_assert_equals(size_t, 100, ms_cardinality(set));
|
||||
|
||||
bool passed = ms_count(set) == 20 && ms_cardinality(set) == 100;
|
||||
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
passed = passed && ms_multiplicity_of(set, i) == 5;
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
ms_free(set);
|
||||
});
|
||||
|
||||
});
|
||||
Reference in new issue
Block a user