From: Marius Gavrilescu Date: Sat, 10 Jun 2017 20:30:24 +0000 (+0300) Subject: Add 2D binary indexed trees X-Git-Tag: 0.002~1 X-Git-Url: http://git.ieval.ro/?a=commitdiff_plain;h=0c7cf8e9cf7b3714bc5fc9e2625d6e4016b8812a;p=algorithm-bit-xs.git Add 2D binary indexed trees --- diff --git a/MANIFEST b/MANIFEST index 112a268..b8cd15a 100644 --- a/MANIFEST +++ b/MANIFEST @@ -7,3 +7,4 @@ typemap XS.xs t/Algorithm-BIT-XS.t lib/Algorithm/BIT/XS.pm +lib/Algorithm/BIT2D/XS.pm diff --git a/XS.xs b/XS.xs index d395dca..940807b 100644 --- a/XS.xs +++ b/XS.xs @@ -52,7 +52,73 @@ void bit_clear(bit *b) { Zero(b->t, b->n, IV); } +typedef struct { + IV n, m; + IV* t; +} bit2d; + +bit2d* bit2d_create(IV n, IV m) { + if(n < 1 || m < 1){ + croak("A dimension is less than 1"); + return 0; + } + n++, m++; + bit2d *ret; + Newx(ret, 1, bit2d); + ret->n = n; + ret->m = m; + Newxz(ret->t, n * m, IV); + return ret; +} + +void bit2d_free(bit2d *b) { + Safefree(b->t); + Safefree(b); +} + +IV bit2d_query(bit2d *b, IV i1, IV i2) { + if(i1 > b->n || i1 < 1) { + croak("Index 1 not in range [1," IVdf "]", b->n); + return 0; + } + if(i2 > b->m || i2 < 1) { + croak("Index 2 not in range [1," IVdf "]", b->m); + return 0; + } + IV ret = 0, i2c = i2; + while(i1) { + i2 = i2c; + while(i2) + ret += b->t[i1 * b->n + i2], i2 -= i2 & -i2; + i1 -= i1 & -i1; + } + return ret; +} + +void bit2d_update(bit2d *b, IV i1, IV i2, IV value) { + if(i1 > b->n || i1 < 1) { + croak("Index 1 not in range [1," IVdf "]", b->n); + return; + } + if(i2 > b->m || i2 < 1) { + croak("Index 2 not in range [1," IVdf "]", b->m); + return; + } + IV i2c = i2; + while(i1 < b->n) { + i2 = i2c; + while(i2 < b->m) + b->t[i1 * b->n + i2] += value, i2 += i2 & -i2; + i1 += i1 & -i1; + } +} + +void bit2d_clear(bit2d *b) { + Zero(b->t, b->n * b->m, IV); +} + typedef bit *Algorithm__BIT__XS; +typedef bit2d *Algorithm__BIT2D__XS; MODULE = Algorithm::BIT::XS PACKAGE = Algorithm::BIT::XS PREFIX = bit_ @@ -67,3 +133,17 @@ IV bit_query(Algorithm::BIT::XS b, IV idx); void bit_update(Algorithm::BIT::XS b, IV idx, IV value); void bit_clear(Algorithm::BIT::XS b); + +MODULE = Algorithm::BIT::XS PACKAGE = Algorithm::BIT2D::XS PREFIX = bit2d_ + +PROTOTYPES: ENABLE + +Algorithm::BIT2D::XS bit2d_create(IV n, IV m); + +void bit2d_free(Algorithm::BIT2D::XS b); + +IV bit2d_query(Algorithm::BIT2D::XS b, IV i1, IV i2); + +void bit2d_update(Algorithm::BIT2D::XS b, IV i1, IV i2, IV value); + +void bit2d_clear(Algorithm::BIT2D::XS b); diff --git a/lib/Algorithm/BIT/XS.pm b/lib/Algorithm/BIT/XS.pm index d9a8f4b..42591f3 100644 --- a/lib/Algorithm/BIT/XS.pm +++ b/lib/Algorithm/BIT/XS.pm @@ -21,7 +21,7 @@ sub get { sub set { my ($b, $idx, $value) = @_; - $b->update($idx, $value - $b->get($idx, $value)) + $b->update($idx, $value - $b->get($idx)) } 1; @@ -93,7 +93,7 @@ Sets I<$bit>[I<$idx>] to I<$value>. =head1 SEE ALSO -L, L +L, L, L =head1 AUTHOR diff --git a/lib/Algorithm/BIT2D/XS.pm b/lib/Algorithm/BIT2D/XS.pm new file mode 100644 index 0000000..d0b872a --- /dev/null +++ b/lib/Algorithm/BIT2D/XS.pm @@ -0,0 +1,111 @@ +package Algorithm::BIT2D::XS; + +use 5.014000; +use strict; +use warnings; + +our $VERSION = '0.001'; + +use Algorithm::BIT::XS; + +sub new { + my ($class, $n, $m) = @_; + create($n, $m); +} + +sub get { + my ($b, $i1, $i2) = @_; + $b->query($i1, $i2) + $b->query($i1 - 1, $i2 - 1) + - $b->query($i1 - 1, $i2) - $b->query($i1, $i2 - 1); +} + +sub set { + my ($b, $i1, $i2, $value) = @_; + $b->update($i1, $i2, $value - $b->get($i1, $i2)) +} + +1; +__END__ + +=encoding utf-8 + +=head1 NAME + +Algorithm::BIT2D::XS - 2D Binary indexed trees / Fenwick trees + +=head1 SYNOPSIS + + use Algorithm::BIT2D::XS; + my $bit = Algorithm::BIT2D::XS->new(100, 100); + $bit->update(1, 2, 5); # bit[1][2] += 5 + $bit->update(3, 3, 6); # bit[3][3] += 6 + say 'bit[1..2][1..10] == ', $bit->query(2, 10); # 5 + say 'bit[1..3][1..2] == ', $bit->query(3, 2); # 5 + say 'bit[1..20][1..10] == ', $bit->query(20, 10); # 11 + + $bit->update(3, 1, 10); # bit[3][1] += 10 + say 'bit[1..3][1..3] == ', $bit->query(3, 3); # 21 + say 'bit[3][3] == ', $bit->get(3, 3); # 6 + + $bit->set(3, 3, 10); # bit[3][3] = 10 + say 'bit[3][3] == ', $bit->get(3, 3); # 10 + + $bit->clear; + say 'bit[1..100][1..10] == ', $bit->query(100, 10); # 0 + $bit->set(100, 10, 5); + say 'bit[1..100][1..10] == ', $bit->query(100, 10); # 5 + +=head1 DESCRIPTION + +A binary indexed tree is a data structure similar to an array of integers. +The two main operations are updating an element and calculating a +prefix sum, both of which run in time logarithmic in the size of the tree. + +=over + +=item Algorithm::BIT2D::XS->B(I<$n>, I<$m>) + +Create a new 2D binary indexed tree of length I<$n> x I<$m>. As binary +indexed trees are 1-indexed, its indexes are [1..I<$n>][1..I<$m>]. +It is initially filled with zeroes. + +=item $bit->B() + +Clears the binary indexed tree (sets all elements to 0). + +=item $bit->B(I<$i1>, I<$i2>) + +Returns the rectangle sum from I<$bit>[1][1] to I<$bit>[I<$i1>][I<$i2>]. + +=item $bit->B(I<$i1>, I<$i2>, I<$value>) + +Adds I<$value> to I<$bit>[I<$i1>][I<$i2>]. + +=item $bit->B(I<$i1>, I<$i2>) + +Returns the value of I<$bit>[I<$i1>][I<$i2>]. + +=item $bit->B(I<$i1>, I<$i2>, I<$value>) + +Sets I<$bit>[I<$i1>][I<$i2>] to I<$value>. + +=back + +=head1 SEE ALSO + +L, L, L + +=head1 AUTHOR + +Marius Gavrilescu, Emarius@ieval.roE + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2017 by Marius Gavrilescu + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.24.1 or, +at your option, any later version of Perl 5 you may have available. + + +=cut diff --git a/t/Algorithm-BIT-XS.t b/t/Algorithm-BIT-XS.t index c6ce19f..c2ee47a 100644 --- a/t/Algorithm-BIT-XS.t +++ b/t/Algorithm-BIT-XS.t @@ -2,8 +2,9 @@ use strict; use warnings; -use Test::More tests => 13; +use Test::More tests => 17; BEGIN { use_ok('Algorithm::BIT::XS') }; +BEGIN { use_ok('Algorithm::BIT2D::XS') }; my $bit = Algorithm::BIT::XS->new(100); is $bit->query(5), 0; @@ -29,3 +30,11 @@ $bit->clear; $bit->set(16,10); is $bit->query(15), 0; is $bit->query(16), 10; + + +my $bit2d = Algorithm::BIT2D::XS->new(100, 50); +is $bit2d->query(5, 5), 0; +$bit2d->update(4, 4, 2); +$bit2d->update(5, 1, 3); +is $bit2d->query(5, 5), 5; +is $bit2d->query(5, 2), 3; diff --git a/typemap b/typemap index a3e1ea5..530a511 100644 --- a/typemap +++ b/typemap @@ -1 +1,2 @@ Algorithm::BIT::XS T_PTROBJ +Algorithm::BIT2D::XS T_PTROBJ