algorithms 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/History.txt +139 -2
  2. data/Manifest +31 -8
  3. data/README +90 -0
  4. data/Rakefile +22 -9
  5. data/algorithms.gemspec +28 -101
  6. data/benchmark.rb +29 -27
  7. data/benchmarks/rbench.rb +16 -0
  8. data/benchmarks/rbench/column.rb +26 -0
  9. data/benchmarks/rbench/group.rb +43 -0
  10. data/benchmarks/rbench/report.rb +53 -0
  11. data/benchmarks/rbench/runner.rb +109 -0
  12. data/benchmarks/rbench/summary.rb +51 -0
  13. data/benchmarks/sorts.rb +33 -0
  14. data/ext/containers/bst/bst.c +205 -0
  15. data/ext/containers/{priority_queue → bst}/extconf.rb +1 -1
  16. data/ext/containers/deque/deque.c +233 -0
  17. data/ext/containers/deque/extconf.rb +4 -0
  18. data/ext/containers/tree_map/extconf.rb +1 -1
  19. data/ext/containers/tree_map/rbtree.c +73 -25
  20. data/lib/algorithms.rb +65 -6
  21. data/lib/algorithms/search.rb +84 -0
  22. data/lib/algorithms/sort.rb +238 -0
  23. data/lib/containers/deque.rb +176 -0
  24. data/lib/containers/heap.rb +451 -111
  25. data/lib/containers/kd_tree.rb +87 -0
  26. data/lib/containers/priority_queue.rb +107 -508
  27. data/lib/containers/queue.rb +62 -23
  28. data/lib/containers/rb_tree_map.rb +398 -0
  29. data/lib/containers/splay_tree_map.rb +274 -0
  30. data/lib/containers/stack.rb +59 -21
  31. data/lib/containers/suffix_array.rb +68 -0
  32. data/lib/containers/trie.rb +182 -0
  33. data/lib/graphs/graph.rb +25 -0
  34. data/spec/bst_spec.rb +31 -0
  35. data/spec/deque_spec.rb +108 -0
  36. data/spec/heap_spec.rb +111 -66
  37. data/spec/kd_tree_spec.rb +89 -0
  38. data/spec/priority_queue_spec.rb +71 -27
  39. data/spec/queue_spec.rb +53 -45
  40. data/spec/rb_tree_map_spec.rb +123 -0
  41. data/spec/search_spec.rb +28 -0
  42. data/spec/sort_spec.rb +28 -0
  43. data/spec/splay_tree_map_spec.rb +102 -0
  44. data/spec/stack_spec.rb +56 -49
  45. data/spec/suffix_array_spec.rb +40 -0
  46. data/spec/trie_spec.rb +59 -0
  47. metadata +54 -32
  48. data/README.txt +0 -58
  49. data/ext/containers/priority_queue/priority_queue.c +0 -948
  50. data/ext/containers/tree_map/Rakefile +0 -4
  51. data/lib/containers/hash.rb +0 -0
  52. data/lib/containers/tree_map.rb +0 -265
  53. data/spec/priority_queue_test.rb +0 -371
  54. data/spec/tree_map_spec.rb +0 -99
@@ -1,4 +1,7 @@
1
- require 'lib/algorithms'
1
+ # :nodoc: all
2
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), 'lib')
3
+ require 'algorithms'
4
+
2
5
  require 'benchmark'
3
6
  include Benchmark
4
7
 
@@ -6,44 +9,43 @@ include Benchmark
6
9
  @random_array = []
7
10
  @num_items = 10000
8
11
  @num_items.times { |x| @random_array << rand(@num_items) }
9
- # @heap = DS::MaxHeap.new(@random_array)
10
-
12
+ # @heap = Containers::MaxHeap.new(@random_array)
13
+ #
11
14
  # benchmark do |bench|
12
15
  # bench.report("Array#max:\t ") do
13
16
  # @num_items.times { @random_array.delete_at(@random_array.index(@random_array.max)) }
14
17
  # end
15
18
  # bench.report("MaxHeap:\t ") do
16
- # @num_items.times { @heap.get_max! }
19
+ # @num_items.times { @heap.max! }
17
20
  # end
18
21
  # end
19
22
 
23
+ # Benchmark Deque
24
+ deque = Containers::RubyDeque.new
25
+ array = []
26
+ benchmark do |bench|
27
+ bench.report("Array:\t ") { 1000000.times { |x| array << x } }
28
+ bench.report("Deque:\t ") { 1000000.times { |x| deque.push_back(x) } }
29
+ end
30
+
20
31
  # Benchmark Search trees
21
- @tree = Containers::TreeMap.new
22
- @ctree = Containers::TreeMap.new
32
+ @rb_tree = Containers::RubyRBTreeMap.new
33
+ @splay_tree = Containers::SplayTreeMap.new
23
34
  @hash = Hash.new
24
35
 
25
36
  benchmark do |bench|
26
- bench.report("Tree: \t") do
27
- @random_array.each { |x| @tree[x] = x }
28
- end
29
-
30
- bench.report("CTree: \t") do
31
- @random_array.each { |x| @ctree[x] = x }
32
- end
33
-
34
- bench.report("Hash: \t") do
35
- @hash.each { |x| @hash[x] = x }
36
- end
37
-
38
- bench.report("Hash: \t") do
39
- @num_items.times { |n| @hash.has_key?(n) }
40
- end
37
+ puts "\nInsertion"
38
+ bench.report("RBTree: \t") { @random_array.each { |x| @rb_tree[x] = x } }
39
+ bench.report("SplayTree: \t") { @random_array.each { |x| @splay_tree[x] = x } }
40
+ bench.report("Hash: \t\t") { @hash.each { |x| @hash[x] = x } }
41
41
 
42
- bench.report("Tree: \t") do
43
- @num_items.times { |n| @tree.contains?(n) }
44
- end
42
+ puts "\nTest has_key?"
43
+ bench.report("RBTree: \t") { @num_items.times { |n| @rb_tree.has_key?(n) } }
44
+ bench.report("SplayTree: \t") { @num_items.times { |n| @splay_tree.has_key?(n) } }
45
+ bench.report("Hash: \t\t") { @num_items.times { |n| @hash.has_key?(n) } }
45
46
 
46
- bench.report("CTree: \t") do
47
- @num_items.times { |n| @ctree.contains?(n) }
48
- end
47
+ puts "\nSorted order"
48
+ bench.report("RBTree: \t") { @rb_tree.each { |k, v| k } }
49
+ bench.report("SplayTree: \t") { @splay_tree.each { |k, v| k } }
50
+ bench.report("Hash: \t\t") { @hash.sort.each { |k, v| k } }
49
51
  end
@@ -0,0 +1,16 @@
1
+ require 'pathname'
2
+ require 'benchmark'
3
+
4
+ dir = Pathname(__FILE__).dirname.expand_path + 'rbench/'
5
+
6
+ require dir + 'runner'
7
+ require dir + 'column'
8
+ require dir + 'group'
9
+ require dir + 'report'
10
+ require dir + 'summary'
11
+
12
+ module RBench
13
+ def self.run(times=1, &block)
14
+ Runner.new(times).run(&block)
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ module RBench
2
+ class Column
3
+ attr_accessor :name, :title, :width, :compare, :default
4
+
5
+ def initialize(runner, name, options = {})
6
+ @runner = runner
7
+ @name = name
8
+ @title = options[:title] || (@name == :times ? "" : @name.to_s.upcase)
9
+ @width = options[:width] || [@title.length,7].max
10
+ @compare = options[:compare]
11
+ @default = @compare ? @compare : options[:default]
12
+ end
13
+
14
+ def to_s(val=title)
15
+ str = case val
16
+ when Array then "%#{width-1}.2f" % (val[0] / val[1]) + "x"
17
+ when Float then "%#{width}.3f" % val
18
+ when Integer then "%#{width}.0f" % val
19
+ when TrueClass then " "*(width/2.0).floor + "X" + " "*(width/2.0).floor
20
+ when String then "%#{width}s" % (val)[0,width]
21
+ when Object then " " * width
22
+ end
23
+ return " #{(str.to_s+" "*width)[0,width]} |"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,43 @@
1
+ module RBench
2
+ class Group
3
+ self.instance_methods.each do |m|
4
+ send(:undef_method, m) unless m =~ /^(__|is_a?|kind_of?|respond_to?|hash|eql?|inspect|instance_eval)/
5
+ end
6
+
7
+ attr_reader :name, :items, :block, :times
8
+
9
+ def initialize(runner, name, times=nil, &block)
10
+ @runner = runner
11
+ @name = name
12
+ @items = []
13
+ @block = block
14
+ @times = times || @runner.times
15
+ end
16
+
17
+ def prepare
18
+ # This just loops through and spawns the reports, and the summary (if exists)
19
+ self.instance_eval(&@block) if @block
20
+ # Now we want to make sure that the summary is
21
+ @items << @items.shift if @items.first.is_a?(Summary)
22
+ end
23
+
24
+ def run
25
+ # Put a separator with the group-name at the top. puts?
26
+ puts @runner.separator(@name)
27
+ # Now loop through the items in this group, and run them
28
+ @items.each{|item| item.run}
29
+ end
30
+
31
+ def report(name,times=@times,&block)
32
+ @items << Report.new(@runner,self,name,times,&block)
33
+ end
34
+
35
+ def summary(name)
36
+ @items.unshift(Summary.new(@runner,self,name)) unless @items.detect{|i| i.is_a?(Summary)}
37
+ end
38
+
39
+ def to_s
40
+ @runner.separator(@name) << @items.map { |item| item.to_s }.join
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,53 @@
1
+ module RBench
2
+ class Report
3
+ self.instance_methods.each do |m|
4
+ send(:undef_method, m) unless m =~ /^(__|is_a?|kind_of?|respond_to?|hash|inspect|instance_eval|eql?)/
5
+ end
6
+
7
+ attr_reader :name, :cells
8
+
9
+ def initialize(runner, group, name, times=nil,&block)
10
+ @runner = runner
11
+ @group = group
12
+ @name = name
13
+ @times = (times || runner.times).ceil
14
+ @cells = {}
15
+ @block = block
16
+
17
+ # Setting the default for all cells
18
+ runner.columns.each {|c| @cells[c.name] = c.name == :times ? "x#{@times}" : c.default }
19
+
20
+ new_self = (class << self; self end)
21
+ @runner.columns.each do |column|
22
+ new_self.class_eval <<-CLASS
23
+ def #{column.name}(val=nil,&block)
24
+ @cells[#{column.name.inspect}] = block ? Benchmark.measure { @times.times(&block) }.real : val
25
+ end
26
+ CLASS
27
+ end
28
+ end
29
+
30
+ def run
31
+ # runs the actual benchmarks. If there is only one column, just evaluate the block itself.
32
+ if @runner.columns.length == 1
33
+ @cells[@runner.columns.first.name] = Benchmark.measure { @times.times(&@block) }.real
34
+ else
35
+ self.instance_eval(&@block)
36
+ end
37
+ # puts its row now that it is complete
38
+ puts to_s
39
+ end
40
+
41
+ def to_s
42
+ out = "%-#{@runner.desc_width}s" % name
43
+ @runner.columns.each do |column|
44
+ value = @cells[column.name]
45
+ value = @cells.values_at(*value) if value.is_a?(Array)
46
+ value = nil if value.is_a?(Array) && value.nitems != 2
47
+
48
+ out << column.to_s(value)
49
+ end
50
+ out << @runner.newline
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,109 @@
1
+ module RBench
2
+ class Runner
3
+ attr_accessor :columns, :items, :times, :width
4
+
5
+ def initialize(times)
6
+ @width = 0
7
+ @times = times
8
+ @columns = []
9
+ @items = []
10
+ end
11
+
12
+ def run(&block)
13
+
14
+ # initiate all the columns, groups, reports, and summaries on top level.
15
+ self.instance_eval(&block)
16
+
17
+ # the groups has not run just yet, but when they do, we really only want
18
+ # to make them initiate their reports, not run them (just yet)
19
+ # when we only have two levels, _every_ report should now be initialized.
20
+ @items.each{|item| item.prepare if item.is_a?(Group)}
21
+
22
+ # We are putting the summary to the back if its there.
23
+ @items << @items.shift if @items.first.is_a?(Summary)
24
+
25
+ # if on columns were set, create a default column
26
+ column(:results, :title => "Results") if @columns.empty?
27
+
28
+ # since we are about to start rendering, we put out the column-header
29
+ puts header
30
+
31
+ # now we are ready to loop through our items and run!
32
+ items.each { |item| item.run if item.respond_to?(:run) }
33
+
34
+ # returning self so people can output it in different formats.
35
+ self
36
+ end
37
+
38
+ def format(options={})
39
+ @width = options.delete(:width) || @width
40
+ end
41
+
42
+ def column(name,options={})
43
+ @columns << Column.new(self,name,options)
44
+ end
45
+
46
+ def group(name,times=nil,&block)
47
+ @items << Group.new(self,name,times,&block)
48
+ end
49
+
50
+ def report(name,times=nil,&block)
51
+ # create an anonymous group, or add it to the last open group.
52
+ group(nil) unless @items.last.is_a?(Group) && !@items.last.block
53
+ # now create the report on the last group
54
+ @items.last.report(name,times,&block)
55
+ end
56
+
57
+ def summary(name)
58
+ # adding the summary to the front, so it is easier to put it last later.
59
+ @items.unshift(Summary.new(self,nil,name)) unless @items.detect{|i| i.is_a?(Summary)}
60
+ end
61
+
62
+ ##
63
+ # convenience-methods
64
+ ##
65
+
66
+ def groups
67
+ @items.select{|item| item.is_a?(Group) }
68
+ end
69
+
70
+ def reports
71
+ # we now want _all_ reports, also those that are part of subgroups
72
+ groups.map{|g| g.items.select{|item| item.is_a?(Report) } }.flatten
73
+ end
74
+
75
+ ##
76
+ # for rendering text. pull out in separate module when to_xml and to_html is in place
77
+ ##
78
+
79
+ def newline
80
+ "\n"
81
+ end
82
+
83
+ def header
84
+ " " * desc_width + @columns.map {|c| c.to_s }.join + newline
85
+ end
86
+
87
+ def desc_width
88
+ @desc_width ||= [items.map{|i| (i.items.map{|r| r.name} << i.name) }.flatten.map{|i| i.to_s.length}.max+8,@width-columns_width].max
89
+ end
90
+
91
+ def columns_width
92
+ @columns.inject(0){ |tot,c| tot += (c.to_s.length) }
93
+ end
94
+
95
+ def width(value=nil)
96
+ header.length-1
97
+ end
98
+
99
+ def separator(title=nil,chr="-",length=width)
100
+ title ? chr*2 + title + chr * (width - title.length - 2) : chr * length
101
+ end
102
+
103
+ def to_s
104
+ out = " " * desc_width + @columns.map {|c| c.to_s }.join + newline
105
+ out << @items.map {|item| item.to_s}.join
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,51 @@
1
+ module RBench
2
+ class Summary
3
+ attr_reader :name, :runner, :cells, :items
4
+ attr_accessor :lines
5
+
6
+ def initialize(runner, group, name)
7
+ @runner = runner
8
+ @group = group
9
+ @name = name
10
+ @cells = {} # A hash with keys as columns, and values being the result
11
+ @items = []
12
+ end
13
+
14
+ def run
15
+ # maybe add convenience-method to group to. group == runner really.
16
+ items = (@group ? @group.items & @runner.reports : @runner.reports)
17
+
18
+ rows = items.map{|item| item.cells.values_at(*@runner.columns.map{|c|c.name}) }
19
+ rows = rows.pop.zip(*rows)
20
+
21
+ @runner.columns.each_with_index do |c,i|
22
+ if c.compare
23
+ value,comparisons = 0,0
24
+ items.each do |item|
25
+ v1,v2 = *item.cells.values_at(*c.compare)
26
+ if v1.kind_of?(Numeric) && v2.kind_of?(Numeric) && v1 != 0 && v2 != 0
27
+ value += v1 / v2
28
+ comparisons += 1
29
+ end
30
+ end
31
+ @cells[c.name] = [value,comparisons] if comparisons > 0
32
+ elsif c.name != :times
33
+ @cells[c.name] = rows[i].compact.select{|r| r.kind_of?(Numeric)}.inject(0){|tot,v| tot += v.to_f }
34
+ end
35
+ end
36
+
37
+ puts to_s
38
+ end
39
+
40
+ def to_s
41
+ out = ""
42
+ out << @runner.separator(nil,"=") + @runner.newline unless @group
43
+ out << "%-#{@runner.desc_width}s" % name
44
+ @runner.columns.each do |column|
45
+ value = @cells[column.name]
46
+ out << column.to_s( value )
47
+ end
48
+ out << @runner.newline
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,33 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '../lib')
2
+ require 'algorithms'
3
+ include Algorithms
4
+
5
+ require 'rbench'
6
+
7
+ RBench.run(5) do
8
+
9
+ sorts = %w(built_in comb_sort heapsort insertion_sort shell_sort quicksort mergesort)
10
+ sorts.each { |sort| self.send(:column, sort.intern) }
11
+
12
+ n = 1000
13
+
14
+ proc = lambda { |scope, ary|
15
+ scope.built_in { ary.dup.sort }
16
+ scope.comb_sort { Sort.comb_sort(ary.dup) }
17
+ scope.heapsort { Sort.heapsort(ary.dup) }
18
+ scope.insertion_sort { Sort.insertion_sort(ary.dup) }
19
+ scope.shell_sort { Sort.shell_sort(ary.dup) }
20
+ scope.quicksort { Sort.quicksort(ary.dup) }
21
+ scope.mergesort { Sort.mergesort(ary.dup) }
22
+ }
23
+
24
+ report "Already sorted" do
25
+ sorted_array = Array.new(n) { rand(n) }.sort
26
+ proc.call(self, sorted_array)
27
+ end
28
+
29
+ report "Random" do
30
+ random_array = Array.new(n) { rand(n) }
31
+ proc.call(self, random_array)
32
+ end
33
+ end
@@ -0,0 +1,205 @@
1
+ #include "ruby.h"
2
+ #include <ctype.h>
3
+
4
+ #ifndef RSTRING_PTR
5
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
6
+ #endif
7
+
8
+ /* for compatibility with Ruby 1.8.5, which doesn't declare RSTRING_LEN */
9
+ #ifndef RSTRING_LEN
10
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
11
+ #endif
12
+
13
+ typedef struct struct_bst_node {
14
+ VALUE key;
15
+ VALUE data;
16
+ struct struct_bst_node *left;
17
+ struct struct_bst_node *right;
18
+ struct struct_bst_node *parent;
19
+ } bst_node;
20
+
21
+
22
+ typedef struct struct_bst_head {
23
+ bst_node *head;
24
+ unsigned int size;
25
+ } bst_head;
26
+
27
+ static VALUE bst_initialize(VALUE self) {
28
+ return self;
29
+ }
30
+
31
+ static void in_order_display (bst_node *root) {
32
+ if (root) {
33
+ in_order_display(root->left);
34
+ rb_yield(rb_assoc_new(root->key,root->data));
35
+ in_order_display(root->right);
36
+ }
37
+ }
38
+
39
+ static int id_compare_operator;
40
+
41
+ static int rb_key_compare(VALUE a, VALUE b) {
42
+ return FIX2INT(rb_funcall((VALUE) a, id_compare_operator, 1, (VALUE) b));
43
+ }
44
+
45
+ static void insert_element(bst_node **root,bst_node *newElement) {
46
+ bst_node *y = NULL;
47
+ bst_node *x = *root;
48
+ while (x != NULL) {
49
+ y = x;
50
+ //if (newElement->key < x->key) x = x->left;
51
+ if (rb_key_compare(newElement->key,x->key) < 0) x = x->left;
52
+ else x = x->right;
53
+ }
54
+ newElement->parent = y;
55
+ if (y == NULL) *root = newElement;
56
+ //else if (newElement->key < y->key) y->left = newElement;
57
+ else if (rb_key_compare(newElement->key,y->key) < 0) y->left = newElement;
58
+ else y->right = newElement;
59
+ }
60
+
61
+
62
+ static bst_node *create_element(VALUE key_data,VALUE data) {
63
+ bst_node *arbit = malloc(sizeof(bst_node));
64
+ arbit->data = data;
65
+ arbit->key = key_data;
66
+ arbit->left = NULL;
67
+ arbit->right = NULL;
68
+ arbit->parent = NULL;
69
+ return arbit;
70
+ }
71
+
72
+
73
+ static bst_node *tree_minimum (bst_node *root) {
74
+ bst_node *x = root;
75
+ while (x->left) x = x->left;
76
+ return x;
77
+ }
78
+
79
+
80
+ static bst_node *tree_maximum (bst_node *root) {
81
+ bst_node *x = root;
82
+ while (x->right) x = x->right;
83
+ return x;
84
+ }
85
+
86
+ static bst_node *node_successor (bst_node *root,bst_node *x) {
87
+ if (x->right) return tree_minimum(x->right);
88
+ bst_node *y = x->parent;
89
+ while (y && x == y->right) {
90
+ x = y;
91
+ y = x->parent;
92
+ }
93
+ return y;
94
+ }
95
+
96
+
97
+ bst_node *delete_node (bst_node **root,bst_node *tobeDeleted) {
98
+ bst_node *y,*x;
99
+
100
+ if ((tobeDeleted->left == NULL) || (tobeDeleted->right == NULL)) y = tobeDeleted;
101
+ else y = node_successor(*root,tobeDeleted);
102
+
103
+ if (y->left) x = y->left;
104
+ else x = y->right;
105
+
106
+ if (x) x->parent = y->parent;
107
+
108
+ if (y->parent == NULL) {
109
+ *root = x;
110
+ return y;
111
+ } else if (y == y->parent->left) {
112
+ y->parent->left = x;
113
+ } else {
114
+ y->parent->right = x;
115
+ }
116
+
117
+ if (tobeDeleted != y) tobeDeleted->key = y->key;
118
+ return y;
119
+ }
120
+
121
+ bst_node *search_node (bst_node *root,VALUE key) {
122
+ bst_node *x = root;
123
+ while (x) {
124
+ //if (x->key == key) return x;
125
+ if (rb_key_compare(x->key,key) == 0) return x;
126
+ //else if (key < x->key) x = x->left;
127
+ else if (rb_key_compare(key,x->key) < 0) x = x->left;
128
+ else x = x->right;
129
+ }
130
+ return NULL;
131
+ }
132
+
133
+ void delete_nodes_recur(bst_node *root) {
134
+ if(root) {
135
+ delete_nodes_recur(root->left);
136
+ if(root) free(root);
137
+ delete_nodes_recur(root->right);
138
+ }
139
+ }
140
+
141
+ static void bst_free_node(void *p) {
142
+ bst_head *headNode = (bst_head *)p;
143
+ delete_nodes_recur(headNode->head);
144
+ }
145
+
146
+ static VALUE bst_alloc(VALUE klass) {
147
+ bst_head *headNode = ALLOC(bst_head);
148
+ headNode->head = NULL;
149
+ headNode->size = 0;
150
+ VALUE obj;
151
+ obj = Data_Wrap_Struct(klass,NULL,bst_free_node,headNode);
152
+ return obj;
153
+ }
154
+
155
+ static VALUE rb_bst_insert_value(VALUE self,VALUE key,VALUE data) {
156
+ bst_head *headNode;
157
+ Data_Get_Struct(self,bst_head,headNode);
158
+ insert_element(&(headNode->head),create_element(key,data));
159
+ headNode->size++;
160
+ return self;
161
+ }
162
+
163
+ /* data structure builds up a stack for traversal, delete can be harmful */
164
+ static VALUE rb_bst_each(VALUE self)
165
+ {
166
+ bst_head *headNode;
167
+ Data_Get_Struct(self,bst_head,headNode);
168
+ in_order_display(headNode->head);
169
+ return Qnil;
170
+ }
171
+
172
+ static VALUE rb_bst_delete(VALUE self,VALUE keyVal) {
173
+ //int key = FIX2INT(keyVal);
174
+ bst_head *headNode;
175
+ Data_Get_Struct(self,bst_head,headNode);
176
+ bst_node *tobeDeleted = search_node(headNode->head,keyVal);
177
+ if(tobeDeleted) {
178
+ headNode->size = headNode->size - 1;
179
+ bst_node *deletedNode = delete_node(&(headNode->head),tobeDeleted);
180
+ return deletedNode->data;
181
+ } else {
182
+ rb_raise(rb_eArgError, "Key was not found");
183
+ return Qnil;
184
+ }
185
+ }
186
+
187
+ static VALUE rb_bst_size(VALUE self) {
188
+ bst_head *headNode;
189
+ Data_Get_Struct(self,bst_head,headNode);
190
+ return INT2FIX(headNode->size);
191
+ }
192
+
193
+ static VALUE mContainers;
194
+
195
+ void Init_CBst() {
196
+ id_compare_operator = rb_intern("<=>");
197
+ mContainers = rb_define_module("Containers");
198
+ VALUE cbst_class = rb_define_class_under(mContainers,"CBst",rb_cObject);
199
+ rb_define_alloc_func(cbst_class,bst_alloc);
200
+ rb_define_method(cbst_class,"initialize",bst_initialize,0);
201
+ rb_define_method(cbst_class,"insert",rb_bst_insert_value,2);
202
+ rb_define_method(cbst_class,"each", rb_bst_each,0);
203
+ rb_define_method(cbst_class,"delete",rb_bst_delete,1);
204
+ rb_define_method(cbst_class,"size",rb_bst_size,0);
205
+ }