rbtree 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +119 -61
- data/LICENSE +1 -1
- data/README +54 -26
- data/extconf.rb +4 -27
- data/rbtree.c +117 -138
- data/test.rb +110 -66
- metadata +45 -35
data/LICENSE
CHANGED
data/README
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
= Ruby/RBTree
|
4
4
|
|
5
|
-
RBTree is a sorted associative collection
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
RBTree is a sorted associative collection that is implemented with
|
6
|
+
Red-Black Tree. The elements of RBTree are ordered and its interface
|
7
|
+
is the almost same as Hash, so simply you can consider RBTree sorted
|
8
|
+
Hash.
|
9
9
|
|
10
10
|
Red-Black Tree is a kind of binary tree that automatically balances
|
11
11
|
by itself when a node is inserted or deleted. Thus the complexity
|
@@ -14,28 +14,48 @@ case. On the other hand the complexity of Hash is O(1). Because
|
|
14
14
|
Hash is unordered the data structure is more effective than
|
15
15
|
Red-Black Tree as an associative collection.
|
16
16
|
|
17
|
-
The
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
17
|
+
The elements of RBTree are sorted with natural ordering (by <=>
|
18
|
+
method) of its keys or by a comparator(Proc) set by readjust
|
19
|
+
method. It means all keys in RBTree should be comparable with each
|
20
|
+
other. Or a comparator that takes two arguments of a key should return
|
21
|
+
negative, 0, or positive depending on the first argument is less than,
|
22
|
+
equal to, or greater than the second one.
|
23
|
+
|
24
|
+
The interface of RBTree is the almost same as Hash and there are a
|
25
|
+
few methods to take advantage of the ordering:
|
26
|
+
|
27
|
+
* lower_bound, upper_bound, bound
|
28
|
+
* first, last
|
29
|
+
* shift, pop
|
30
|
+
* reverse_each
|
31
|
+
|
32
|
+
Note: while iterating RBTree (e.g. in a block of each method), it is
|
33
|
+
not modifiable, or TypeError is thrown.
|
34
|
+
|
35
|
+
RBTree supoorts pretty printing using pp.
|
36
|
+
|
37
|
+
This library contains two classes. One is RBTree and the other is
|
38
|
+
MultiRBTree that is a parent class of RBTree. RBTree does not allow
|
39
|
+
duplications of keys but MultiRBTree does.
|
40
|
+
|
41
|
+
require "rbtree"
|
42
|
+
|
43
|
+
rbtree = RBTree["c", 10, "a", 20]
|
44
|
+
rbtree["b"] = 30
|
45
|
+
p rbtree["b"] # => 30
|
46
|
+
rbtree.each do |k, v|
|
47
|
+
p [k, v]
|
48
|
+
end # => ["a", 20] ["b", 30] ["c", 10]
|
49
|
+
|
50
|
+
mrbtree = MultiRBTree["c", 10, "a", 20, "e", 30, "a", 40]
|
51
|
+
p mrbtree.lower_bound("b") # => ["c", 10]
|
52
|
+
mrbtree.bound("a", "d") do |k, v|
|
53
|
+
p [k, v]
|
54
|
+
end # => ["a", 20] ["a", 40] ["c", 10]
|
35
55
|
|
36
56
|
== Requirement
|
37
57
|
|
38
|
-
* Ruby 1.
|
58
|
+
* Ruby 1.8.x
|
39
59
|
|
40
60
|
== Install
|
41
61
|
|
@@ -43,7 +63,7 @@ MultiRBTree that allows duplicates of keys is also available.
|
|
43
63
|
|
44
64
|
or download a tarball from the link below
|
45
65
|
|
46
|
-
* ((<"Ruby/RBTree 0.2.
|
66
|
+
* ((<"Ruby/RBTree 0.2.1"|URL:rbtree-0.2.1.tar.gz>))
|
47
67
|
|
48
68
|
and then
|
49
69
|
|
@@ -57,13 +77,15 @@ and then
|
|
57
77
|
|
58
78
|
$ ruby test.rb
|
59
79
|
|
60
|
-
== Incomplete
|
80
|
+
== Incomplete Documents
|
61
81
|
|
62
82
|
$ rdoc rbtree.c
|
63
83
|
|
84
|
+
or online documents at ((<URL:http://rbtree.rubyforge.org/>)).
|
85
|
+
|
64
86
|
== License
|
65
87
|
|
66
|
-
MIT License. Copyright (c) 2002-2004, 2007 OZAWA Takuma.
|
88
|
+
MIT License. Copyright (c) 2002-2004, 2007, 2009 OZAWA Takuma.
|
67
89
|
|
68
90
|
dict.c and dict.h are modified copies that are originally in Kazlib
|
69
91
|
written by Kaz Kylheku. Copyright is held by Kaz Kylheku, see dict.c
|
@@ -75,4 +97,10 @@ and dict.h for the license. The web page of Kazlib is at
|
|
75
97
|
Bug fixes, suggestions and other feedbacks are welcomed. Please mail
|
76
98
|
me at burningdowntheopera at yahoo dot co dot jp.
|
77
99
|
|
100
|
+
== Links
|
101
|
+
|
102
|
+
* ((<RAA - ruby-rbtree|URL:http://raa.ruby-lang.org/project/ruby-rbtree/>))
|
103
|
+
* ((<RubyForge: rbtree: Project Info|URL:http://rubyforge.org/projects/rbtree/>))
|
104
|
+
* ((<URL:http://www.geocities.co.jp/SiliconValley-PaloAlto/3388/rbtree/README.html>))
|
105
|
+
|
78
106
|
=end
|
data/extconf.rb
CHANGED
@@ -1,34 +1,11 @@
|
|
1
1
|
require 'mkmf'
|
2
|
-
require 'rbconfig'
|
3
2
|
|
4
|
-
if
|
3
|
+
if $DEBUG
|
5
4
|
$CFLAGS << ' -std=c89 -pedantic -Wall -Wno-long-long'
|
6
|
-
|
7
|
-
|
8
|
-
$defs << '-DNDEBUG'
|
9
|
-
|
10
|
-
print 'checking for allocation framework... '
|
11
|
-
if Object.respond_to?(:allocate)
|
12
|
-
print "yes\n"
|
13
|
-
$defs << '-DHAVE_OBJECT_ALLOCATE'
|
5
|
+
$defs << ' -Dinline=__inline'
|
14
6
|
else
|
15
|
-
|
7
|
+
$defs << '-DNDEBUG'
|
16
8
|
end
|
17
9
|
|
18
|
-
have_func('
|
19
|
-
have_func('rb_block_proc')
|
20
|
-
have_func('rb_yield_values')
|
21
|
-
have_func('rb_marshal_dump')
|
22
|
-
have_func('rb_marshal_load')
|
23
|
-
|
24
|
-
print 'checking for inline keyword... '
|
25
|
-
inline = ['inline', '__inline', '__inline__', ''].find {|e|
|
26
|
-
try_link(<<EOS)
|
27
|
-
int main() { return 0; }
|
28
|
-
#{e} void foo() {}
|
29
|
-
EOS
|
30
|
-
}
|
31
|
-
print "#{inline}\n"
|
32
|
-
$defs << "-Dinline=#{inline}"
|
33
|
-
|
10
|
+
have_func('rb_enumeratorize')
|
34
11
|
create_makefile('rbtree')
|
data/rbtree.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* MIT License
|
3
|
-
* Copyright (c) 2002-2004, 2007 OZAWA Takuma
|
3
|
+
* Copyright (c) 2002-2004, 2007, 2009 OZAWA Takuma
|
4
4
|
*/
|
5
5
|
#include <ruby.h>
|
6
6
|
#include <version.h>
|
@@ -8,12 +8,11 @@
|
|
8
8
|
#include <stdarg.h>
|
9
9
|
#include "dict.h"
|
10
10
|
|
11
|
-
#define RBTREE_IN_ITERATION FL_USER1
|
12
11
|
#define RBTREE_PROC_DEFAULT FL_USER2
|
13
12
|
#define HASH_PROC_DEFAULT FL_USER2
|
14
13
|
|
15
|
-
#ifndef
|
16
|
-
#define
|
14
|
+
#ifndef HAVE_RB_ENUMERATORIZE
|
15
|
+
#define RETURN_ENUMERATOR(obj, argc, argv) ((void)0)
|
17
16
|
#endif
|
18
17
|
|
19
18
|
VALUE RBTree;
|
@@ -24,12 +23,6 @@ static ID id_cmp;
|
|
24
23
|
static ID id_call;
|
25
24
|
static ID id_default;
|
26
25
|
|
27
|
-
#ifndef HAVE_RB_MARSHAL_DUMP
|
28
|
-
static VALUE rb_mMarshal;
|
29
|
-
static ID id_dump;
|
30
|
-
static ID id_load;
|
31
|
-
#endif
|
32
|
-
|
33
26
|
typedef struct {
|
34
27
|
dict_t* dict;
|
35
28
|
VALUE ifnone;
|
@@ -51,41 +44,12 @@ typedef struct {
|
|
51
44
|
|
52
45
|
/*********************************************************************/
|
53
46
|
|
54
|
-
#ifndef HAVE_RB_BLOCK_PROC
|
55
|
-
static VALUE
|
56
|
-
rb_block_proc()
|
57
|
-
{
|
58
|
-
return rb_f_lambda();
|
59
|
-
}
|
60
|
-
#endif
|
61
|
-
|
62
|
-
#ifndef HAVE_RB_YIELD_VALUES
|
63
|
-
static VALUE
|
64
|
-
rb_yield_values(int n, ...)
|
65
|
-
{
|
66
|
-
int i;
|
67
|
-
va_list ap;
|
68
|
-
VALUE ary = rb_ary_new2(n);
|
69
|
-
|
70
|
-
va_start(ap, n);
|
71
|
-
for (i = 0; i < n; i++)
|
72
|
-
rb_ary_push(ary, va_arg(ap, VALUE));
|
73
|
-
va_end(ap);
|
74
|
-
return rb_yield(ary);
|
75
|
-
}
|
76
|
-
#endif
|
77
|
-
|
78
47
|
static int
|
79
48
|
cmpint(VALUE i, VALUE a, VALUE b)
|
80
49
|
{
|
81
|
-
#if RUBY_VERSION_CODE >= 180
|
82
50
|
return rb_cmpint(i, a, b);
|
83
|
-
#else
|
84
|
-
return rb_cmpint(i);
|
85
|
-
#endif
|
86
51
|
}
|
87
52
|
|
88
|
-
|
89
53
|
static void
|
90
54
|
rbtree_free(rbtree_t* rbtree)
|
91
55
|
{
|
@@ -187,19 +151,6 @@ VALUE rbtree_update(VALUE, VALUE);
|
|
187
151
|
|
188
152
|
/*********************************************************************/
|
189
153
|
|
190
|
-
#ifndef HAVE_OBJECT_ALLOCATE
|
191
|
-
/*
|
192
|
-
*
|
193
|
-
*/
|
194
|
-
VALUE
|
195
|
-
rbtree_s_new(int argc, VALUE* argv, VALUE klass)
|
196
|
-
{
|
197
|
-
VALUE rbtree = rbtree_alloc(klass);
|
198
|
-
rb_obj_call_init(rbtree, argc, argv);
|
199
|
-
return rbtree;
|
200
|
-
}
|
201
|
-
#endif
|
202
|
-
|
203
154
|
static int
|
204
155
|
hash_to_rbtree_i(VALUE key, VALUE value, VALUE rbtree)
|
205
156
|
{
|
@@ -214,17 +165,48 @@ hash_to_rbtree_i(VALUE key, VALUE value, VALUE rbtree)
|
|
214
165
|
VALUE
|
215
166
|
rbtree_s_create(int argc, VALUE* argv, VALUE klass)
|
216
167
|
{
|
217
|
-
|
168
|
+
long i;
|
218
169
|
VALUE rbtree;
|
219
|
-
|
170
|
+
|
220
171
|
if (argc == 1) {
|
172
|
+
VALUE tmp;
|
173
|
+
|
174
|
+
if (klass == RBTree && CLASS_OF(argv[0]) == MultiRBTree) {
|
175
|
+
rb_raise(rb_eTypeError, "can't convert MultiRBTree to RBTree");
|
176
|
+
}
|
177
|
+
|
221
178
|
if (rb_obj_is_kind_of(argv[0], klass)) {
|
222
179
|
rbtree = rbtree_alloc(klass);
|
223
180
|
rbtree_update(rbtree, argv[0]);
|
224
181
|
return rbtree;
|
225
|
-
}
|
182
|
+
}
|
183
|
+
|
184
|
+
tmp = rb_check_convert_type(argv[0], T_HASH, "Hash", "to_hash");
|
185
|
+
if (!NIL_P(tmp)) {
|
186
|
+
rbtree = rbtree_alloc(klass);
|
187
|
+
st_foreach(RHASH(tmp)->tbl, hash_to_rbtree_i, rbtree);
|
188
|
+
return rbtree;
|
189
|
+
}
|
190
|
+
|
191
|
+
tmp = rb_check_array_type(argv[0]);
|
192
|
+
if (!NIL_P(tmp)) {
|
226
193
|
rbtree = rbtree_alloc(klass);
|
227
|
-
|
194
|
+
for (i = 0; i < RARRAY(tmp)->len; i++) {
|
195
|
+
VALUE v = rb_check_array_type(RARRAY(tmp)->ptr[i]);
|
196
|
+
if (NIL_P(v)) {
|
197
|
+
continue;
|
198
|
+
}
|
199
|
+
switch(RARRAY(v)->len) {
|
200
|
+
case 1:
|
201
|
+
rbtree_aset(rbtree, RARRAY(v)->ptr[0], Qnil);
|
202
|
+
break;
|
203
|
+
case 2:
|
204
|
+
rbtree_aset(rbtree, RARRAY(v)->ptr[0], RARRAY(v)->ptr[1]);
|
205
|
+
break;
|
206
|
+
default:
|
207
|
+
continue;
|
208
|
+
}
|
209
|
+
}
|
228
210
|
return rbtree;
|
229
211
|
}
|
230
212
|
}
|
@@ -556,6 +538,7 @@ each_i(dnode_t* node, void* arg)
|
|
556
538
|
VALUE
|
557
539
|
rbtree_each(VALUE self)
|
558
540
|
{
|
541
|
+
RETURN_ENUMERATOR(self, 0, NULL);
|
559
542
|
return rbtree_for_each(self, each_i, NULL);
|
560
543
|
}
|
561
544
|
|
@@ -576,6 +559,7 @@ each_pair_i(dnode_t* node, void* arg)
|
|
576
559
|
VALUE
|
577
560
|
rbtree_each_pair(VALUE self)
|
578
561
|
{
|
562
|
+
RETURN_ENUMERATOR(self, 0, NULL);
|
579
563
|
return rbtree_for_each(self, each_pair_i, NULL);
|
580
564
|
}
|
581
565
|
|
@@ -596,6 +580,7 @@ each_key_i(dnode_t* node, void* arg)
|
|
596
580
|
VALUE
|
597
581
|
rbtree_each_key(VALUE self)
|
598
582
|
{
|
583
|
+
RETURN_ENUMERATOR(self, 0, NULL);
|
599
584
|
return rbtree_for_each(self, each_key_i, NULL);
|
600
585
|
}
|
601
586
|
|
@@ -616,6 +601,7 @@ each_value_i(dnode_t* node, void* arg)
|
|
616
601
|
VALUE
|
617
602
|
rbtree_each_value(VALUE self)
|
618
603
|
{
|
604
|
+
RETURN_ENUMERATOR(self, 0, NULL);
|
619
605
|
return rbtree_for_each(self, each_value_i, NULL);
|
620
606
|
}
|
621
607
|
|
@@ -629,6 +615,7 @@ rbtree_each_value(VALUE self)
|
|
629
615
|
VALUE
|
630
616
|
rbtree_reverse_each(VALUE self)
|
631
617
|
{
|
618
|
+
RETURN_ENUMERATOR(self, 0, NULL);
|
632
619
|
return rbtree_reverse_for_each(self, each_pair_i, NULL);
|
633
620
|
}
|
634
621
|
|
@@ -679,26 +666,13 @@ rbtree_initialize_copy(VALUE self, VALUE other)
|
|
679
666
|
return self;
|
680
667
|
}
|
681
668
|
|
682
|
-
#ifndef HAVE_RB_OBJ_INIT_COPY
|
683
|
-
/*
|
684
|
-
*
|
685
|
-
*/
|
686
|
-
VALUE
|
687
|
-
rbtree_clone(VALUE self)
|
688
|
-
{
|
689
|
-
VALUE clone = rbtree_alloc(CLASS_OF(self));
|
690
|
-
rbtree_initialize_copy(clone, self);
|
691
|
-
return clone;
|
692
|
-
}
|
693
|
-
#endif
|
694
|
-
|
695
669
|
/*
|
696
670
|
*
|
697
671
|
*/
|
698
672
|
VALUE
|
699
673
|
rbtree_values_at(int argc, VALUE* argv, VALUE self)
|
700
674
|
{
|
701
|
-
|
675
|
+
long i;
|
702
676
|
VALUE ary = rb_ary_new();
|
703
677
|
|
704
678
|
for (i = 0; i < argc; i++)
|
@@ -720,7 +694,10 @@ select_i(dnode_t* node, void* ary)
|
|
720
694
|
VALUE
|
721
695
|
rbtree_select(VALUE self)
|
722
696
|
{
|
723
|
-
VALUE ary
|
697
|
+
VALUE ary;
|
698
|
+
|
699
|
+
RETURN_ENUMERATOR(self, 0, NULL);
|
700
|
+
ary = rb_ary_new();
|
724
701
|
rbtree_for_each(self, select_i, (void*)ary);
|
725
702
|
return ary;
|
726
703
|
}
|
@@ -843,7 +820,8 @@ VALUE
|
|
843
820
|
rbtree_delete_if(VALUE self)
|
844
821
|
{
|
845
822
|
rbtree_delete_if_arg_t arg;
|
846
|
-
|
823
|
+
|
824
|
+
RETURN_ENUMERATOR(self, 0, NULL);
|
847
825
|
rbtree_modify(self);
|
848
826
|
arg.self = self;
|
849
827
|
arg.list = NULL;
|
@@ -857,7 +835,10 @@ rbtree_delete_if(VALUE self)
|
|
857
835
|
VALUE
|
858
836
|
rbtree_reject_bang(VALUE self)
|
859
837
|
{
|
860
|
-
|
838
|
+
dictcount_t count;
|
839
|
+
|
840
|
+
RETURN_ENUMERATOR(self, 0, NULL);
|
841
|
+
count = dict_count(DICT(self));
|
861
842
|
rbtree_delete_if(self);
|
862
843
|
if (count == dict_count(DICT(self)))
|
863
844
|
return Qnil;
|
@@ -874,7 +855,7 @@ rbtree_reject(VALUE self)
|
|
874
855
|
}
|
875
856
|
|
876
857
|
static VALUE
|
877
|
-
rbtree_shift_pop(VALUE self, const int
|
858
|
+
rbtree_shift_pop(VALUE self, const int shift)
|
878
859
|
{
|
879
860
|
dict_t* dict = DICT(self);
|
880
861
|
dnode_t* node;
|
@@ -889,10 +870,10 @@ rbtree_shift_pop(VALUE self, const int mode)
|
|
889
870
|
return IFNONE(self);
|
890
871
|
}
|
891
872
|
|
892
|
-
if (
|
893
|
-
node = dict_first(dict);
|
894
|
-
else
|
873
|
+
if (shift)
|
895
874
|
node = dict_last(dict);
|
875
|
+
else
|
876
|
+
node = dict_first(dict);
|
896
877
|
ret = ASSOC(node);
|
897
878
|
dict_delete_free(dict, node);
|
898
879
|
return ret;
|
@@ -1088,7 +1069,12 @@ to_hash_i(dnode_t* node, void* hash)
|
|
1088
1069
|
VALUE
|
1089
1070
|
rbtree_to_hash(VALUE self)
|
1090
1071
|
{
|
1091
|
-
VALUE hash
|
1072
|
+
VALUE hash;
|
1073
|
+
if (CLASS_OF(self) == MultiRBTree) {
|
1074
|
+
rb_raise(rb_eTypeError, "can't convert MultiRBTree to Hash");
|
1075
|
+
}
|
1076
|
+
|
1077
|
+
hash = rb_hash_new();
|
1092
1078
|
rbtree_for_each(self, to_hash_i, (void*)hash);
|
1093
1079
|
RHASH(hash)->ifnone = IFNONE(self);
|
1094
1080
|
if (FL_TEST(self, RBTREE_PROC_DEFAULT))
|
@@ -1307,7 +1293,7 @@ rbtree_bound(int argc, VALUE* argv, VALUE self)
|
|
1307
1293
|
}
|
1308
1294
|
|
1309
1295
|
static VALUE
|
1310
|
-
rbtree_first_last(VALUE self, const int
|
1296
|
+
rbtree_first_last(VALUE self, const int first)
|
1311
1297
|
{
|
1312
1298
|
dict_t* dict = DICT(self);
|
1313
1299
|
dnode_t* node;
|
@@ -1319,7 +1305,7 @@ rbtree_first_last(VALUE self, const int mode)
|
|
1319
1305
|
return IFNONE(self);
|
1320
1306
|
}
|
1321
1307
|
|
1322
|
-
if (
|
1308
|
+
if (first)
|
1323
1309
|
node = dict_first(dict);
|
1324
1310
|
else
|
1325
1311
|
node = dict_last(dict);
|
@@ -1335,7 +1321,7 @@ rbtree_first_last(VALUE self, const int mode)
|
|
1335
1321
|
VALUE
|
1336
1322
|
rbtree_first(VALUE self)
|
1337
1323
|
{
|
1338
|
-
return rbtree_first_last(self,
|
1324
|
+
return rbtree_first_last(self, 1);
|
1339
1325
|
}
|
1340
1326
|
|
1341
1327
|
/*
|
@@ -1347,7 +1333,7 @@ rbtree_first(VALUE self)
|
|
1347
1333
|
VALUE
|
1348
1334
|
rbtree_last(VALUE self)
|
1349
1335
|
{
|
1350
|
-
return rbtree_first_last(self,
|
1336
|
+
return rbtree_first_last(self, 0);
|
1351
1337
|
}
|
1352
1338
|
|
1353
1339
|
/*
|
@@ -1359,11 +1345,11 @@ rbtree_last(VALUE self)
|
|
1359
1345
|
*
|
1360
1346
|
* Sets a proc to compare keys and readjusts elements using the given
|
1361
1347
|
* block or a Proc object given as the argument. The block takes two
|
1362
|
-
* key
|
1363
|
-
* first argument is less than, equal to, or greater than the
|
1364
|
-
* one. If no block is given it just readjusts elements using
|
1365
|
-
* comparison block. If nil is given as the argument it sets
|
1366
|
-
* comparison block.
|
1348
|
+
* arguments of a key and returns negative, 0, or positive depending
|
1349
|
+
* on the first argument is less than, equal to, or greater than the
|
1350
|
+
* second one. If no block is given it just readjusts elements using
|
1351
|
+
* current comparison block. If nil is given as the argument it sets
|
1352
|
+
* default comparison block.
|
1367
1353
|
*/
|
1368
1354
|
VALUE
|
1369
1355
|
rbtree_readjust(int argc, VALUE* argv, VALUE self)
|
@@ -1482,20 +1468,6 @@ rbtree_pretty_print_cycle(VALUE self, VALUE pp)
|
|
1482
1468
|
|
1483
1469
|
/*********************************************************************/
|
1484
1470
|
|
1485
|
-
#ifndef HAVE_RB_MARSHAL_DUMP
|
1486
|
-
static VALUE
|
1487
|
-
rb_marshal_dump(VALUE obj, VALUE port)
|
1488
|
-
{
|
1489
|
-
return rb_funcall(rb_mMarshal, id_dump, 2, obj, port);
|
1490
|
-
}
|
1491
|
-
|
1492
|
-
static VALUE
|
1493
|
-
rb_marshal_load(VALUE port)
|
1494
|
-
{
|
1495
|
-
return rb_funcall(rb_mMarshal, id_load, 1, port);
|
1496
|
-
}
|
1497
|
-
#endif
|
1498
|
-
|
1499
1471
|
static each_return_t
|
1500
1472
|
to_flatten_ary_i(dnode_t* node, void* ary)
|
1501
1473
|
{
|
@@ -1554,10 +1526,10 @@ rbtree_s_load(VALUE klass, VALUE str)
|
|
1554
1526
|
/*********************************************************************/
|
1555
1527
|
|
1556
1528
|
/*
|
1557
|
-
* RBTree is a sorted associative collection
|
1558
|
-
*
|
1559
|
-
*
|
1560
|
-
*
|
1529
|
+
* RBTree is a sorted associative collection that is implemented with
|
1530
|
+
* Red-Black Tree. The elements of RBTree are ordered and its interface
|
1531
|
+
* is the almost same as Hash, so simply you can consider RBTree sorted
|
1532
|
+
* Hash.
|
1561
1533
|
*
|
1562
1534
|
* Red-Black Tree is a kind of binary tree that automatically balances
|
1563
1535
|
* by itself when a node is inserted or deleted. Thus the complexity
|
@@ -1565,25 +1537,45 @@ rbtree_s_load(VALUE klass, VALUE str)
|
|
1565
1537
|
* case. On the other hand the complexity of Hash is O(1). Because
|
1566
1538
|
* Hash is unordered the data structure is more effective than
|
1567
1539
|
* Red-Black Tree as an associative collection.
|
1540
|
+
*
|
1541
|
+
* The elements of RBTree are sorted with natural ordering (by <=>
|
1542
|
+
* method) of its keys or by a comparator(Proc) set by readjust
|
1543
|
+
* method. It means all keys in RBTree should be comparable with each
|
1544
|
+
* other. Or a comparator that takes two arguments of a key should return
|
1545
|
+
* negative, 0, or positive depending on the first argument is less than,
|
1546
|
+
* equal to, or greater than the second one.
|
1547
|
+
*
|
1548
|
+
* The interface of RBTree is the almost same as Hash and there are a
|
1549
|
+
* few methods to take advantage of the ordering:
|
1550
|
+
*
|
1551
|
+
* * lower_bound, upper_bound, bound
|
1552
|
+
* * first, last
|
1553
|
+
* * shift, pop
|
1554
|
+
* * reverse_each
|
1555
|
+
*
|
1556
|
+
* Note: while iterating RBTree (e.g. in a block of each method), it is
|
1557
|
+
* not modifiable, or TypeError is thrown.
|
1558
|
+
*
|
1559
|
+
* RBTree supoorts pretty printing using pp.
|
1560
|
+
*
|
1561
|
+
* This library contains two classes. One is RBTree and the other is
|
1562
|
+
* MultiRBTree that is a parent class of RBTree. RBTree does not allow
|
1563
|
+
* duplications of keys but MultiRBTree does.
|
1568
1564
|
*
|
1569
|
-
*
|
1570
|
-
*
|
1571
|
-
*
|
1572
|
-
*
|
1573
|
-
*
|
1574
|
-
*
|
1575
|
-
*
|
1576
|
-
*
|
1577
|
-
*
|
1578
|
-
*
|
1579
|
-
*
|
1580
|
-
*
|
1581
|
-
*
|
1582
|
-
*
|
1583
|
-
* Pretty printing is available for RBTree by using pp.rb. The output
|
1584
|
-
* of pp is easier than p to read. Just call Kernel#pp for the object.
|
1585
|
-
*
|
1586
|
-
* MultiRBTree that allows duplicates of keys is also available.
|
1565
|
+
* require "rbtree"
|
1566
|
+
*
|
1567
|
+
* rbtree = RBTree["c", 10, "a", 20]
|
1568
|
+
* rbtree["b"] = 30
|
1569
|
+
* p rbtree["b"] # => 30
|
1570
|
+
* rbtree.each do |k, v|
|
1571
|
+
* p [k, v]
|
1572
|
+
* end # => ["a", 20] ["b", 30] ["c", 10]
|
1573
|
+
*
|
1574
|
+
* mrbtree = MultiRBTree["c", 10, "a", 20, "e", 30, "a", 40]
|
1575
|
+
* p mrbtree.lower_bound("b") # => ["c", 10]
|
1576
|
+
* mrbtree.bound("a", "d") do |k, v|
|
1577
|
+
* p [k, v]
|
1578
|
+
* end # => ["a", 20] ["a", 40] ["c", 10]
|
1587
1579
|
*/
|
1588
1580
|
void Init_rbtree()
|
1589
1581
|
{
|
@@ -1591,21 +1583,13 @@ void Init_rbtree()
|
|
1591
1583
|
RBTree = rb_define_class("RBTree", MultiRBTree);
|
1592
1584
|
|
1593
1585
|
rb_include_module(MultiRBTree, rb_mEnumerable);
|
1594
|
-
|
1595
|
-
#ifdef HAVE_OBJECT_ALLOCATE
|
1586
|
+
|
1596
1587
|
rb_define_alloc_func(MultiRBTree, rbtree_alloc);
|
1597
|
-
|
1598
|
-
rb_define_singleton_method(MultiRBTree, "new", rbtree_s_new, -1);
|
1599
|
-
#endif
|
1588
|
+
|
1600
1589
|
rb_define_singleton_method(MultiRBTree, "[]", rbtree_s_create, -1);
|
1601
1590
|
|
1602
1591
|
rb_define_method(MultiRBTree, "initialize", rbtree_initialize, -1);
|
1603
|
-
|
1604
|
-
#ifdef HAVE_RB_OBJ_INIT_COPY
|
1605
1592
|
rb_define_method(MultiRBTree, "initialize_copy", rbtree_initialize_copy, 1);
|
1606
|
-
#else
|
1607
|
-
rb_define_method(MultiRBTree, "clone", rbtree_clone, 0);
|
1608
|
-
#endif
|
1609
1593
|
|
1610
1594
|
rb_define_method(MultiRBTree, "to_a", rbtree_to_a, 0);
|
1611
1595
|
rb_define_method(MultiRBTree, "to_s", rbtree_to_s, 0);
|
@@ -1667,11 +1651,6 @@ void Init_rbtree()
|
|
1667
1651
|
|
1668
1652
|
rb_define_method(MultiRBTree, "_dump", rbtree_dump, 1);
|
1669
1653
|
rb_define_singleton_method(MultiRBTree, "_load", rbtree_s_load, 1);
|
1670
|
-
#ifndef HAVE_RB_MARSHAL_DUMP
|
1671
|
-
rb_mMarshal = rb_path2class("Marshal");
|
1672
|
-
id_dump = rb_intern("dump");
|
1673
|
-
id_load = rb_intern("load");
|
1674
|
-
#endif
|
1675
1654
|
|
1676
1655
|
id_bound = rb_intern("bound");
|
1677
1656
|
id_cmp = rb_intern("<=>");
|