]> iEval git - algorithm-bit-xs.git/commitdiff
Add 2D binary indexed trees
authorMarius Gavrilescu <marius@ieval.ro>
Sat, 10 Jun 2017 20:30:24 +0000 (23:30 +0300)
committerMarius Gavrilescu <marius@ieval.ro>
Sat, 10 Jun 2017 20:30:24 +0000 (23:30 +0300)
MANIFEST
XS.xs
lib/Algorithm/BIT/XS.pm
lib/Algorithm/BIT2D/XS.pm [new file with mode: 0644]
t/Algorithm-BIT-XS.t
typemap

index 112a26852f3eeefd19d12cc791eea54ae8c8cd39..b8cd15a32018d11f0b7a6ddef833bb82726e1b90 100644 (file)
--- 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 d395dca861e16b88106a6df98cca485e8e792dc3..940807b509e110ac8e6f9bdf7b32aeccf36d908e 100644 (file)
--- 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);
index d9a8f4ba4d1a04f60e23a411c708f60663414f5f..42591f360956d7aa625ee51008003b6bd8f58805 100644 (file)
@@ -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<Algorithm::BIT>, L<https://en.wikipedia.org/wiki/Fenwick_tree>
+L<Algorithm::BIT>, L<Algorithm::BIT2D::XS>, L<https://en.wikipedia.org/wiki/Fenwick_tree>
 
 =head1 AUTHOR
 
diff --git a/lib/Algorithm/BIT2D/XS.pm b/lib/Algorithm/BIT2D/XS.pm
new file mode 100644 (file)
index 0000000..d0b872a
--- /dev/null
@@ -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<new>(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<clear>()
+
+Clears the binary indexed tree (sets all elements to 0).
+
+=item $bit->B<query>(I<$i1>, I<$i2>)
+
+Returns the rectangle sum from I<$bit>[1][1] to I<$bit>[I<$i1>][I<$i2>].
+
+=item $bit->B<update>(I<$i1>, I<$i2>, I<$value>)
+
+Adds I<$value> to I<$bit>[I<$i1>][I<$i2>].
+
+=item $bit->B<get>(I<$i1>, I<$i2>)
+
+Returns the value of I<$bit>[I<$i1>][I<$i2>].
+
+=item $bit->B<set>(I<$i1>, I<$i2>, I<$value>)
+
+Sets I<$bit>[I<$i1>][I<$i2>] to I<$value>.
+
+=back
+
+=head1 SEE ALSO
+
+L<Algorithm::BIT>, L<Algorithm::BIT::XS>, L<https://en.wikipedia.org/wiki/Fenwick_tree>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=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
index c6ce19f40cae5e9d012131cc752a85c415a1a0c2..c2ee47a3cee96a3c35df85d77af74a37722d69ae 100644 (file)
@@ -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 a3e1ea50dfe0bdbcf89d986b593aee46c1768c86..530a51191bd75ace2786afadc025033b5cb2a3a6 100644 (file)
--- a/typemap
+++ b/typemap
@@ -1 +1,2 @@
 Algorithm::BIT::XS T_PTROBJ
+Algorithm::BIT2D::XS T_PTROBJ
This page took 0.115189 seconds and 4 git commands to generate.