diff --git a/Makefile b/Makefile index bbf4fb9..fcb2d36 100755 --- a/Makefile +++ b/Makefile @@ -5,9 +5,15 @@ NAME = ditvector CC = g++ CFLAGS = -Wall -g -std=c++20 -.PHONY: all test clean info +.PHONY: all example test clean info -all: test +all: example + +example: example.o + @$(CC) $(CFLAGS) -o example example.o + +example.o: example.cpp avl.hpp bit_vector.hpp bit_vector.cpp + @$(CC) $(CFLAGS) -c example.cpp test: test.o @$(CC) $(CFLAGS) -o test test.o diff --git a/README.md b/README.md index 5fa27e5..9accc84 100644 --- a/README.md +++ b/README.md @@ -2,30 +2,33 @@ A dynamic bitvector that support rank and select queries. -The datastructure allows for one template argument that defines the size of the bitblocks stored in leaf. +The datastructure allows for one template argument that defines the size of the bitblocks stored in the leafs. This parameter can be used to select the appropriate trade-off between space and time complexity. As a sensible default a size of 512 bits is used. ## Operations The datastructure supports the following instructions which all have logarithmic runtime. -* insert(index, true/false) -* del(index) -* set(index) -* unset(index) -* flip(index) -* rank(index, true/false) -* select(index, true/false) +* `insert(index, true/false)` +* `del(index)` +* `set(index)` +* `unset(index)` +* `flip(index)` +* `rank(index, true/false)` +* `select(index, true/false)` +* `complement()` +* `size()` returns number of bits in bitvector +* `extract()` returns all bits as std::vector ## Usage ```c++ -BitVector<> bv; +BitVector<16> bv; bv.insert(0, false); bv.insert(0, true); -bv.access(0); // true -bv.rank(1, true); // 1 +bv.access(0); // 1 +bv.rank(1, true); // 1 bv.flip(0); -bv.rank(1, true); // 0 +bv.rank(1, true); // 0 ``` diff --git a/bit_vector.cpp b/bit_vector.cpp index 00e7afe..ca70c6d 100644 --- a/bit_vector.cpp +++ b/bit_vector.cpp @@ -81,6 +81,11 @@ void BitVector::complement() { complement(this->root); } +template +uint32_t BitVector::size() { + return size(this->root); +} + // collect all the bits in the bitvector and return it as one consecutive bool vector template std::vector BitVector::extract() { @@ -295,6 +300,14 @@ void BitVector::complement(BV_Node *node) { } } +// calculate the number of bits that are stored in the structure +template +uint32_t BitVector::size(BV_Node *node) { + if (!node) + return 0; + return node->nums + size(node->r); +} + // find the node (always a leaf) that contains the bit at the position index // index is updated as well to locate the bit inside the leaf block template diff --git a/bit_vector.hpp b/bit_vector.hpp index 1073eb1..3714ca4 100644 --- a/bit_vector.hpp +++ b/bit_vector.hpp @@ -54,6 +54,7 @@ class BitVector : public AVL> { uint32_t select(BV_Node *, uint32_t, bool); bool access(BV_Node *, uint32_t); void complement(BV_Node *); + uint32_t size(BV_Node *); BV_Node *find_block(BV_Node *, uint32_t*); #ifdef ADS_DEBUG @@ -85,6 +86,7 @@ class BitVector : public AVL> { uint32_t select(uint32_t, bool); bool access(uint32_t); void complement(); + uint32_t size(); std::vector extract(); #ifdef ADS_DEBUG diff --git a/example.cpp b/example.cpp new file mode 100644 index 0000000..a660c73 --- /dev/null +++ b/example.cpp @@ -0,0 +1,17 @@ +#include "bit_vector.cpp" + +const size_t BLOCK_SIZE = 64; + +int main(int argc, char *argv[]) { + + BitVector bv; + bv.insert(0, false); + bv.insert(0, true); + std::cout << bv.access(0) << std::endl; + std::cout << bv.rank(1, true) << std::endl; + bv.flip(0); + std::cout << bv.rank(1, true) << std::endl; + bv.del(0); + std::cout << bv.size() << std::endl; +} +